Home > Back-end >  Cannot pass value from one view to another(SwiftUI)
Cannot pass value from one view to another(SwiftUI)

Time:11-23

I want to take 2 numbers input in the textField and print the multiplication of the two numbers in the third view(ResultView).

I have 3 views :-

a - ContentView(This view contains the navigation destination)

struct ContentView: View {
    @State private var path = NavigationPath()

        var body: some View {
            NavigationStack(path: $path) {

            Button {
              path.append("EnterNumberView")
                  } label: {
                      Text("Multiply")
                }
                .navigationDestination(for: String.self) { string in
                    switch string {
                    case "EnterNumberView":
                        EnterNumberView(path: $path)
                    case "ResultView":
                        ResultView()
                    default:
                        Text("Unknown")
                    }
                }
            }
        }
    }

b - EnterNumberView(Taking input two numbers)

struct EnterNumberView: View {
    @Binding var path: NavigationPath
    @State var input1: String = ""
    @State var input2: String = ""

        var calculation: String {
            //check if both fields have text else no need for message
            guard input1.isEmpty == false, input2.isEmpty == false else { return "" }

            //check if both are numbers else we need to print "Error"
            guard let m = Double(input1), let n  = Double(input2) else { return "Error" }

            let product = m * n
            return String(format: "%.2f", product)
        }

    var body: some View {
        VStack {
            TextField("Enter First Number", text: $input1)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Enter Second Number", text: $input2)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
            Button {
                path.append("ResultView")
            } label: {
                Text("Tap to see result")
            }

        }
    }
    
}

c - ResultView(I want to print the result here)

struct ResultView: View {
    var body: some View {
     Text("Your result is \(calculation)") //Cannot find calculation in scope 
    }
}

CodePudding user response:

You got 2 possibilities here:

  • create the result var in the ContentView and pass it along the same way you pass the path.

  • or create a ObservableObject that holds you State that is passed allong into the environment.

This example shows a possible implementation with a Viewmodel:

class Viewmodel: ObservableObject{
    // these published values hold the state of your application
    // and notify the view to refresh if something changed
    @Published var input1: String = ""
    @Published var input2: String = ""
    @Published var result: String = ""
    
    func calculation() {
        //check if both fields have text else no need for message
        guard input1.isEmpty == false, input2.isEmpty == false else { return }
        
        //check if both are numbers else we need to print "Error"
        guard let m = Double(input1), let n  = Double(input2) else { return }
        
        let product = m * n
        result = String(format: "%.2f", product)
    }
}

struct ContentView: View {
    @State private var path = NavigationPath()
    // create the viewmodel here
    @StateObject private var viewmodel = Viewmodel()
    var body: some View {
        NavigationStack(path: $path) {
            
            Button {
                path.append("EnterNumberView")
            } label: {
                Text("Multiply")
            }
            .navigationDestination(for: String.self) { string in
                switch string {
                case "EnterNumberView":
                    EnterNumberView(path: $path)
                    // add the viewmodel to the environment
                        .environmentObject(viewmodel)
                case "ResultView":
                    ResultView()
                    // add the viewmodel to the environment
                        .environmentObject(viewmodel)
                default:
                    Text("Unknown")
                }
            }
        }
    }
}

struct EnterNumberView: View {
    @Binding var path: NavigationPath
    // pull the viewmodel from the environment
    @EnvironmentObject private var viewmodel: Viewmodel
    
    var body: some View {
        VStack {
            // reference the viewmodel input1 here
            TextField("Enter First Number", text: $viewmodel.input1)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Enter Second Number", text: $viewmodel.input2)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            // navigation
            Button {
                path.append("ResultView")
            } label: {
                Text("Tap to see result")
            }
        }
    }
}

struct ResultView: View {
    // pull the viewmodel from the environment
    @EnvironmentObject private var viewmodel: Viewmodel
    var body: some View {
        // reference the result from the viewmodel
        Text("Your result is \(viewmodel.result)")
            .onAppear{
                // perform calculation
                viewmodel.calculation()
            }
    }
}
  • Related