Swiftui Textfield Resets Value and Ignores Binding

SwiftUI TextField resets value and ignores binding

Here you go!

class ViewModel: ObservableObject {
@Published var s = "Default String"
}

struct ContentView: View {
@StateObject private var vm = ViewModel()
var body: some View {
TextField("S:", text: $vm.s)
.padding()
}
}

For use in multiple views, in every view where you'd like to use the model add:

@EnvironmentObject private var vm: ViewModel 

But don't forget to inject the model to the main view:

ContentView().environmentObject(ViewModel())

SwiftUI textfield proxy binding code to ignore spaces not working?

No, we should not return, there should be assignment, because it generates feedback.

It can be like

     TextField(placeholder, text: Binding(
get: { self.input },
set: {
var newValue = $0
newValue.removeAll { $0 == " " } // << here !!
self.input = newValue
}))

Capture Textfield value without hitting return key in SwiftUI

Firstly, add @State variable 'year':

@State private var year: Int = 0

Secondly, pass Binding to TextField 'text' parameter and use formatter inside, like this:

        TextField("Year", text: Binding<String>(
get: { String(year) },
set: {
if let value = NumberFormatter().number(from: $0) {
self.year = value.intValue
print("Year: \(year)")
}
}
))

It will print 'year' value until something else but number will be pressed on the keyboard.
To leave only number input you can set keyboardType to your TextField:

.keyboardType(UIKeyboardType.numberPad)

Recognize changes in SwiftUI TextField with double value

On iOS 15 you can use TextField ("Hello", value: $someDoubleValue, formatter: <your NumberFormatter here>) and the value propagates fine.

On iOS 14, it doesn't seem to work binding a TextField to a Double value with a formatter.

So the following works fine in iOS 15, but does not work in iOS 14.

Note The double value is nested here because this is a code snippet taken from what I'm working on right now.

public class MyViewModel: ObservableObject {
@Published var child: ChildObject
}

public class ChildObject: Identifiable, ObservableObject {
@Published var doubleValue: Double
}

public struct FancyPantsView: View {
@ObservedObject var viewModel: MyViewModel

public var body: some View {
VStack {
TextField ("Hello", value: $viewModel.child.doubleValue, formatter: amountFormatter)
.keyboardType(.decimalPad)
}
}

let amountFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.zeroSymbol = ""
return formatter
}()
}

SwiftUI TextField not updating in sibling View (with video)

Use @Binding instead of @State

It is important to remember that TextField is actually a SwiftUI View (via inheritance). The parent child relationship is actually TaskRow -> TextField.

@State is used for representing the 'state' of a view. While this value can be passed around, it's not meant to be written to by other views (it has a single source of truth).

In the case above, I am actually passing title (via $ prefix) to another view while expecting either the parent or child to modify the title property. @Binding supports 2 way communication between views or a property and view.

@State Apple Docs: https://developer.apple.com/documentation/swiftui/state

@Binding Apple Docs: https://developer.apple.com/documentation/swiftui/binding

Jared Sinclair's Wrapper Rules: https://jaredsinclair.com/2020/05/07/swiftui-cheat-sheet.html

Changing the TaskRow and TaskDetail views fixed the behavior:

TaskRow.swift


import SwiftUI
import CoreData

struct TaskRow: View {

@Environment(\.managedObjectContext) var context
@ObservedObject var task: Task

@Binding private var title: String

init(task: Task) {
self.task = task
self._title = Binding(get: {
return task.title ?? ""
}, set: {
task.title = $0
})
print("INIT - TaskRow Initialized: title=\(task.title ?? ""), completed=\(task.completed)")
}

var body: some View {
HStack {
TextField("Task Name", text: self.$title) {
self.save()
}.foregroundColor(.black)
Spacer()
Text("\(self.task.position)")
Button(action: {
self.task.completed.toggle()
self.save()
}, label: {
Image(systemName: self.task.completed ? "checkmark.square" : "square")
}).buttonStyle(BorderlessButtonStyle())
}
}
}

extension TaskRow {
func save() {
try? self.context.save()
print("SAVE - TaskRow")
}
}

TaskDetail.swift


import SwiftUI

struct TaskDetail: View {

@Environment(\.managedObjectContext) var context
@ObservedObject var task: Task

@Binding private var title: String

init(task: Task) {
self.task = task
self._title = Binding(get: {
return task.title ?? ""
}, set: {
task.title = $0
})
print("INIT - TaskDetail Initialized: title=\(task.title ?? ""), completed=\(task.completed)")
}

var body: some View {
Form {
Section {
TextField("Task Name", text: self.$title) {
self.save()
}.foregroundColor(.black)
}
Section {
Button(action: {
self.task.completed.toggle()
self.save()
}, label: {
Image(systemName: self.task.completed ? "checkmark.square" : "square")
}).buttonStyle(BorderlessButtonStyle())
}
}
}
}

extension TaskDetail {
func save() {
try? self.context.save()
print("SAVE - TaskDetail")
}
}

SwiftUI @Binding update doesn't refresh view

You have not misunderstood anything. A View using a @Binding will update when the underlying @State change, but the @State must be defined within the view hierarchy. (Else you could bind to a publisher)

Below, I have changed the name of your ContentView to OriginalContentView and then I have defined the @State in the new ContentView that contains your original content view.

import SwiftUI

struct OriginalContentView: View {
@Binding var isSelected: Bool

var body: some View {
Button(action: {
self.isSelected.toggle()
}) {
Text(isSelected ? "Selected" : "Not Selected")
}
}
}

struct ContentView: View {
@State private var selected = false

var body: some View {
OriginalContentView(isSelected: $selected)
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}


Related Topics



Leave a reply



Submit