Home > Net >  Dynamically access TextField in SwiftUI
Dynamically access TextField in SwiftUI

Time:12-09

I am creating a TextField dynamically inside VStack. Here TextFields are created as follows:

struct Input: View {
    
    var title: String
    @State var value:String
    var disableInputMode:Bool = true

    var body: some View {                
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value)
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()        
    }
}

and these TextFields depend on some other data fields (which are decided at run time):

ScrollView {
    VStack {
        ForEach(detailsViewModel.details) { datum in
            Input(title: datum.title, value: datum.detail!)
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()

Now, when a user enters data and tries to apply, I couldn't find how to get those inputs from other views. From the example in this case — from the above view.

CodePudding user response:

Use onChange modifier to detect TextField value changes and update it to your model.

struct Input: View {
    
    var title: String
    @State var value:String
    var disableInputMode:Bool = false
    
    var onTextChange: ((String) -> Void)?

    var body: some View {
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value)
                .onChange(of: value) {
                    // Called each time value changes.
                    if onTextChange != nil {
                        onTextChange!($0)
                    }
                }
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()
    }
}

You can use it like

ScrollView {
    VStack {
        ForEach(detailsViewModel.details) { datum in
            Input(title: datum.title, value: datum.detail) { newValue in
                // Each time you will get the update
                // Do what ever you want to do with the new value
                // something ike
                // detailsViewModel.update(value: newValue, forItem: datum.id)
                print("Text value for \(datum.id) :", newValue)
            }
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()
  • Related