Clearing TextField

I have a form with a TextField that takes in string values to save to an array. I use the onCommit to store the entered value into the array and to then clear the TextField value. Debug statements show that the value, called newTag, is indeed cleared, however this is not reflected in the view. Can anyone help me understand this behavior and how to get the functionality I’m looking for?

struct ContentView: View {
    @State private var tags = [String]()
    @State private var newTag = ""

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("New Tag")) {
                    TextField("Enter a new tag", text: $newTag, onCommit: {
                        self.addNewTag()
                    })
                }

                Section(header: Text("Tags")) {
                    ForEach(tags, id: \.self) { tag in
                        Text(tag)
                    }
                }
            }

        }
    }

    private func addNewTag() {
        guard !newTag.isEmpty else { return }
        tags.append(newTag)
        newTag = ""
    }
}

Welcome to the community!

You should use TextField with the onSubmit modifier instead of using onCommit as a parameter

The one with onCommit is deprecated, see here.

TextField(text: $newTag) {
    Text("Enter a new tag")
}
.onSubmit {
    addNewTag()
}
1 Like

@pavlobot

Hi Ryan,

Welcome to the community.

It seems to be a timing issue and something to do with how .onCommit is handled. I would have expected that field to be cleared too.

If you add a button below the TextField and after entering the new item to be added, Tap the button to run the function addNewTag(), it works fine. For some weird reason that does not happen when using .onCommit.

struct ContentView: View {
    @State private var tags = [String]()
    @State private var newTag = ""

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("New Tag")) {
                    TextField("Enter a new tag", text: $newTag, onCommit: {
                        addNewTag()
                    })
                    Button("Add Item") {
                        addNewTag()
                    }
                    .buttonStyle(.borderedProminent)
                }

                Section(header: Text("Tags")) {
                    ForEach(tags, id: \.self) { tag in
                        Text(tag)
                    }
                }
            }

        }
    }

    private func addNewTag() {
        guard !newTag.isEmpty else { return }
        tags.append(newTag)
        newTag = ""
    }
}

I would contend that this is a bug but I am still using Xcode 14.2 and still running Monterey so have no idea if Ventura and Xcode 14.3 would be different.

If you want to continue to use just the onCommit method then you would need to add a very short delay before clearing the TextField like this example:

struct ContentView: View {
    @State private var tags = [String]()
    @State private var newTag = ""

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("New Tag")) {
                    TextField("Enter a new tag", text: $newTag, onCommit: {
                        addNewTag()
                    })
//                    Button("Add Item") {
//                        addNewTag()
//                    }
//                    .buttonStyle(.borderedProminent)
                }

                Section(header: Text("Tags")) {
                    ForEach(tags, id: \.self) { tag in
                        Text(tag)
                    }
                }
            }

        }
    }

    private func addNewTag() {
        guard !newTag.isEmpty else { return }
        tags.append(newTag)
        //  This introduces a 0.1 second delay.
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            newTag = ""
        }
    }
}

So I still think it’s a bug in Xcode/iOS16

If you run the code on a real device the outcome is the same.

1 Like