0

Is there a way to capture the value in the TextField without hitting the return key? I have a TextField that I would like to capture the value (years) without hitting the return key. onEditingChanged is triggered only when the field has focus or left focus onComit is triggered only when the return key is hit.

The scenario I am looking at is when I enter "5", for example, in the field and hit "Done", I would like to capture the new value not the existing value.

                    TextField("Number of Years...", value: $years, formatter: integerFormatter, onEditingChanged: { _ in
                        print("OnEditingChanged: \(years)")
                    },
                    onCommit: {
                        print("\(years)")
                    })
RXP
  • 517
  • 4
  • 18

2 Answers2

1

Edit: Apparently with Formatters the value doesn't just update live. A pattern you could try would be having the text field set a @State String and have .onChange trigger a formatting function ... or have a get/set Binding that runs that function for you.

In this way, any button push to exit the view can pul the live raw String from the user input, as well as set that String to whatever formatted version you want.

If focus change is an issue, you might pick stuff up from: https://www.youtube.com/watch?v=SYBmMugnol0&feature=emb_rel_pause

=============

So, teehee, you might laugh, but you already have it working.

Add

.onChange(of: years) { print($0) }

and you'll see what I mean. The @State property is already delivering you a live feed. If you're using Combine to drive some sort of processing pipeline, you might want to deduplicate and and debounce. Apologies if you're not a beginner and what I just wrote was pedantic.

Ryan
  • 1,252
  • 6
  • 15
  • I thought this would work but for some reason it does not trigger the onChange closure. Not sure why – RXP Jan 15 '21 at 05:16
  • That's quite odd. It prints right now for me on a SwiftUI MacOS app. Same goes for having a button press print the State var. – Ryan Jan 15 '21 at 05:31
  • Are you using "onEditingChanged" ? That's just a bool for start and stop of editing. .onChange is a separate function applied anywhere in that view. – Ryan Jan 15 '21 at 05:32
  • I am not using onEditingChanged, I changed it to .onChange. did you check on IOS simulator? – RXP Jan 15 '21 at 05:35
  • Ah, your block is the Formatter. I didn't know this behavior before as I applied formatters via a VM instead or only on commit. Updating the answer. – Ryan Jan 15 '21 at 05:44
  • Re: simulator, yes, I ran it. Apologies for not copying and pasting your example and realizing it was the formatter version of TextField that was the problem. To be fair to you/me, the documentation isn't explicit on that, but it does give us a clue in how Apple calls the person name formatter on commit. – Ryan Jan 15 '21 at 05:50
1

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)