Learn Courses My Dashboard

TextField Updating Theory Question

Hi

I have the interesting behaviour that a TextField updates changes to the bound data when the user presses enter after changing a value. The onCommit code is then called. However, when one simply clicks off on another field after making the changes, the updates don’t happen. Clearly, I am doing something wrong. Any pointers greatly appreciated.

TextField("", value: $community.people[idx].age, 
                    formatter: formatter,
                    onCommit: {
                         print("Committing data")
                    })

The data classes are as follows:

class Person: ObservableObject {
    @Published var name:String
    @Published var age:Int
    @Published var gender:String
    
    init(name:String, age:Int, gender:String) {
        self.name = name
        self.age = age
        self.gender = gender
    }
}

class Community: ObservableObject {
    @Published var people:[Person] = [Person]()
    @Published var aveAge:Double = 0
    
    func calcAveAge() {
        aveAge = 0
        for i in 0..<people.count {
            aveAge += Double(people[i].age) / Double(people.count)
        }
    }
    
    init() {
        self.people.append(Person(name: "John", age: 24, gender: "M"))
        self.people.append(Person(name: "Sarah", age: 21, gender: "F"))
        self.people.append(Person(name: "Charles", age: 65, gender: "M"))
    }
}

and the view struct is as follows:

struct EditView: View {
    
    @ObservedObject var community:Community
    
    let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        return formatter
    }()
    
    var body: some View {
        
        List {
            ForEach(0..<community.people.count, id: \.self) { idx in
                
                VStack {
                    HStack {
                        Text("Name:")
                        Spacer()
                        TextField("", text: $community.people[idx].name)
                        Spacer()
                    }
                    HStack {
                        Text("Age:")
                        TextField("", value: $community.people[idx].age, formatter: formatter,
                                  onCommit: {
                                     print("Committing data")
                                  })
                        Spacer()
                    }
                    HStack {
                        Text("Gender:")
                        TextField("", text: $community.people[idx].gender)
                        Spacer()
                    }
                }
            }
        }

    }
}

Nope, that’s the way onCommit works. Try using onEditingChanged instead. It will supply you with a Bool indicating whether editing is ongoing or completed and will fire when you click outside the TextField.

Thanks! I will try that.

One more question: Isn’t the TextField supposed to update the bound data when the user taps off the field automatically, or am I supposed to do the updating manually in onEditingChanged?

It updates the bound value while the user is editing it.

I find that editing text does update automatically as expected, however, numbers don’t. In my numeric edit field:

TextField("", value: $person.age, formatter: formatter)

if I don’t press enter, the value does not seem to get stored. If I enter a numeric value and then simply go back to the previous screen, the value is not stored. Is my NumberFormatter to blame?

    let formatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        return formatter
    }()

I have encountered that before myself and I believe it to be a bug in SwiftUI. I can’t check right now but IIRC I solved it using an onChange handler to watch the value bound to the text parameter.