Reputation: 7636
I'm trying to execute an action every time a textField
's value is changed.
@Published var value: String = ""
var body: some View {
$value.sink { (val) in
print(val)
}
return TextField($value)
}
But I get below error.
Cannot convert value of type 'Published' to expected argument type 'Binding'
Upvotes: 12
Views: 15483
Reputation: 1499
@Published is one of the most useful property wrappers in SwiftUI, allowing us to create observable objects that automatically announce when changes occur that means whenever an object with a property marked @Published is changed, all views using that object will be reloaded to reflect those changes.
import SwiftUI
struct ContentView: View {
@ObservedObject var textfieldData = TextfieldData()
var body: some View {
TextField("Input:", text: $textfieldData.data)
}
}
class TextfieldData: ObservableObject{
@Published var data: String = ""
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Upvotes: 0
Reputation: 629
You can observe TextField
value by using ways,
import SwiftUI
import Combine
struct ContentView: View {
@State private var Text1 = ""
@State private var Text2 = ""
@ObservedObject var viewModel = ObserveTextFieldValue()
var body: some View {
//MARK: TextField with Closures
TextField("Enter text1", text: $Text1){
editing in
print(editing)
}onCommit: {
print("Committed")
}
//MARK: .onChange Modifier
TextField("Enter text2", text: $Text2).onChange(of: Text2){
text in
print(text)
}
//MARK: ViewModel & Publisher(Combine)
TextField("Enter text3", text: $viewModel.value)
}
}
class ObserveTextFieldValue: ObservableObject {
@Published var value: String = ""
private var cancellables = Set<AnyCancellable>()
init() {
$value.sink(receiveValue: {
val in
print(val)
}).store(in: &cancellables)
}
}
Upvotes: 0
Reputation: 27353
In your code, $value
is a publisher, while TextField
requires a binding. While you can change from @Published
to @State
or even @Binding
, that can't observe the event when the value is changed.
It seems like there is no way to observe a binding.
An alternative is to use ObservableObject
to wrap your value type, then observe the publisher ($value
).
class MyValue: ObservableObject {
@Published var value: String = ""
init() {
$value.sink { ... }
}
}
Then in your view, you have have the binding $viewModel.value
.
struct ContentView: View {
@ObservedObject var viewModel = MyValue()
var body: some View {
TextField($viewModel.value)
}
}
Upvotes: 9
Reputation: 1387
I don't use combine for this. This it's working for me:
TextField("write your answer here...",
text: Binding(
get: {
return self.query
},
set: { (newValue) in
self.fetch(query: newValue) // any action you need
return self.query = newValue
}
)
)
I have to say it's not my idea, I read it in this blog: SwiftUI binding: A very simple trick
Upvotes: 7
Reputation: 4503
This should be a non-fragile way of doing it:
class MyData: ObservableObject {
var value: String = "" {
willSet(newValue) {
print(newValue)
}
}
}
struct ContentView: View {
@ObservedObject var data = MyData()
var body: some View {
TextField("Input:", text: $data.value)
}
}
Upvotes: 24
Reputation: 2685
If you want to observe value
then it should be a State
@State var value: String = ""
Upvotes: 2