SwiftUI - how to update a item in a struct using a textfield and .onchange

Viewed 1166

I have the following code

struct ContentView: View {
@ObservedObject var list = ModelList.shared
var body: some View {
    NavigationView {
        List(list.sorted()) {object in
            NavigationLink(destination: ModelView(object: object)) {
                Text(object.title)
            }
        }
    }
 }
}

struct ModelView: View {
 @State var object: ModelObject

 var body: some View {
    VStack {
        Text(object.title)
        TextField("Label", text: self.$object.text) // xxxxx Error on this line
            .onChange(of: self.$object.text) { newValue in
                print("Text changed to \(self.$object.text)!")
                        }
        
        Button("Use") {
            self.object.updateDate = Date()
            print("title: \(object.title) - text: \(object.text) - date: \(object.updateDate)")
                ModelList.shared.objectWillChange.send()
        }
    }
 }
}

class ModelObject: ObservableObject {
 @Published var updateDate: Date = Date()
 let title: String
 var text: String
 init(title: String) {
    self.title = title
    self.text = ""
    print(self)
 }
}

I do get the error - Instance method 'onChange(of:perform:)' requires that 'Binding' conform to 'Equatable' on line XXXXX

However if I remove the textfield on change line then it compiles and have the code working. But I want to have some action be done when the Textfield get changed and the data to be saved in the struct in the array?

What am I missing here? Thank you.

1 Answers

.onChange(of:perform:) doesn't take a Binding. Just pass the value. The same is true in the print statement:

TextField("Label", text: self.$object.text)
    .onChange(of: self.object.text) { newValue in      // removed $
        print("Text changed to \(self.object.text)!")  // removed $
                }

Here is a minimal testable example that demonstrates the problem:

struct ContentView: View {
    @State private var string = "hello"
    
    var body: some View {
        TextField("Label", text: self.$string)
        .onChange(of: self.$string) { newValue in     // remove $ here
            print("Text changed to \(self.$string)")  // remove $ here
        }
    }
}
Related