I've got a view with two text fields and a save button. How can I possibly change my button's state depending on the contents of the text fields (I'd like to enable the button only in case all text fields are not empty)? Here's my current code:
// The variables associated with text fields
@State var name: String = ""
@State var type: String = ""
// I'd like to associate this variable with
// my button's disabled / enabled state,
// but the function responsible for it doesn't accept bindings
@State var canSave: Bool = false
var body: some View {
Form {
TextField("Name", text: $name)
TextField("Type", text: $type)
Button(action: {
// ...
}, label: {
Text("Save")
})
.disabled(!canSave) // no bindings allowed here; what to use indead?
}
}
I have an idea that I should use combineLatest
from the newest Combine framework. But whatever I try to google leads me to RxSwift-related topics and not actual Combine implementation.
You seem to have a misconception about how SwiftUI works. It doesn't depend for downhill data flow on bindings. It depends purely on State variables. Uphill flow depends on bindings, but you've got those just where you need them (except that your code is wrong: you've bound both text fields to the same binding).
So in a simple case like this, you don't need a binding or Combine. You have State variables and that's all you need:
struct ContentView: View {
@State var name: String = ""
@State var type: String = ""
var body: some View {
Form {
TextField("Name", text: $name)
TextField("Type", text: $type)
Button(action: {
// ...
}, label: {
Text("Save")
}).disabled(name.isEmpty || type.isEmpty)
}
}
}
Now, if you had many text fields to validate instead of just one or two, then sure, you could use publish and subscribe to combine them into a single Bool. But let's get the basic principles right first.
You can add some codes at the end of the View. It's just for simple logic, otherwise, you may need to create some models.
var body: some View {
Form {
TextField("Name", text: $name)
TextField("Type", text: $type)
Button(action: {
// ...
}, label: {
Text("Save")
})
.disabled(!canSave) // no bindings allowed here; what to use indead?
}.onReceive(Publishers.CombineLatest(Just( name.isEmpty), Just(type.isEmpty))){
self.canSave = !($0.0 || $0.1)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With