Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set initial value for a TextField in SwiftUI - compare new and old value

Tags:

swiftui

I have seen a lot of examples and tutorial of how to use an empty TextField for collecting new values, but none that shows how to use a TextField to edit a value.

In my use-case, I want the TextField to be prepopulated/prefilled with data from my viewmodel, then as user edits the data, a Save button should be enabled. In my form, I also have a navigationlink that leads to a sub-page where the user can select something from a list, and then be routed back to the form.

It behaves as described as long I use an empty field; the user can type something temporary in the field, navigate to the sub page, and the temp value is still like it was when he left.

struct TextFieldDemo: View {

    var model:String    // Actual a more complex view model
    @State var editedValue:String = ""

    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Group{
                Text("Some label")
                TextField("Placeholder text", text: $editedValue)
            }
            Divider()
            Text("Some navigation link to push in a page where " +
                "the user can select something from a list and click back...")

            // If the user starts to edit the textfield - follows a navigation link and comes back
            // he should be able to continue edit the field where he left of - the text field should
            // not have been reset to the original value.

            Button(action: {
                // Call some save function in the ViewModel
                },label: {
                    Text("SAVE")
                }
            ).disabled(model == editedValue)
        }.onAppear(){
            // I could have done something like:
            //   self.editedValue = model
            // but it seems like this will fire if the user navigates into the described page and reset
            // the TextField to the model value.
        }
    }
}

struct TextFieldDemo_Previews: PreviewProvider {
    static var previews: some View {
        TextFieldDemo(model: "The old value")
    }
}
like image 380
Andreas Aarsland Avatar asked Dec 23 '22 18:12

Andreas Aarsland


1 Answers

To initialize the text field with the value from your model, you need to define your own initializer and use the State(wrappedValue:) initializer for @State vars:

struct TextFieldDemo: View {

    var model:String    // Actual a more complex view model
    @State var editedValue: String

    init(model: String) {
        self.model = model
        self._editedValue = State(wrappedValue: model) // _editedValue is State<String>
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Group{
                Text("Some label")
                TextField("Placeholder text", text: $editedValue)
            }
            Divider()
            Text("Some navigation link to push in a page where " +
                "the user can select something from a list and click back...")

            // If the user starts to edit the textfield - follows a navigation link and comes back
            // he should be able to continue edit the field where he left of - the text field should
            // not have been reset to the original value.

            Button(action: {
                // Call some save function in the ViewModel
                },label: {
                    Text("SAVE")
                }
            ).disabled(model == editedValue)
        }.onAppear(){
            // I could have done something like:
            //   self.editedValue = model
            // but it seems like this will fire if the user navigates into the described page and reset
            // the TextField to the model value.
        }
    }
}

struct TextFieldDemo_Previews: PreviewProvider {
    static var previews: some View {
        TextFieldDemo(model: "The old value")
    }
}
like image 68
Sam Avatar answered Jun 18 '23 05:06

Sam