I have a SwiftUI Form with a backing ViewModel. I wish to enable a Save button when the ViewModel changed. I have the following code:
class ViewModel: ObservableObject {
@Published var didUpdate = false
@Published var name = "Qui-Gon Jinn"
@Published var color = "green"
private var cancellables: [AnyCancellable] = []
init() {
self.name.publisher.combineLatest(self.color.publisher)
.sink { _ in
NSLog("Here")
self.didUpdate = true
}
.store(in: &self.cancellables)
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
Form {
Toggle(isOn: self.$viewModel.didUpdate) {
Text("Did update:")
}
TextField("Enter name", text: self.$viewModel.name)
TextField("Lightsaber color", text: self.$viewModel.color)
}
.textFieldStyle(RoundedBorderTextFieldStyle())
.navigationBarItems(
trailing:
Button("Save") { NSLog("Saving!") }
.disabled(!self.viewModel.didUpdate)
)
}
}
}
There are two problems with this code.
First problem is that upon instantiation of the ViewModel, the log will show "Here", and thus set didUpdate to true. The second problem is that when the user changes the viewmodel via the textfields, it doesn't actually fire the publishers.
How should these problems be fixed?
(I've thought of adding didSet{} to each property in the ViewModel but that is very ugly when there are lots of properties. I've also thought of adding modifiers to the textfields, but I really prefer putting this code in the ViewModel, because a network update could also change the ViewModel).