I'm trying to capture the text typed in a TextEditor, store it in a variable and update what is displayed on the TextEditor itself. I'm using the .onChange()
to trigger and capture what is being typed, store it in a variable, and change the current text being displayed. But the problem is that, .onChange()
is being called twice: First, when i type the text inside the TextEditor; and Second, when i try to set a different character for the view itself.
struct ChatView: View {
@State var chatTextInput: String = ""
@State var oldChatValue: String = ""
@State var newChatValue: String = ""
var body: some View {
VStack {
TextEditor(text: $chatTextInput)
.onChange(of: chatTextInput) { newValue in
oldChatValue = "a"
newChatValue = newValue.last.map{String($0)}!
chatTextInput = oldChatValue
}
}
}
}
For exemple, if i type qwerty, newChatValue
is printed as Qawaearataya and chatTextInput
receives aaaaaaaaaaaa
Any clues on how to prevent the .onChange to being triggered the second time, when i set the new character for the TextEditor text?
Thanks a lot!
CodePudding user response:
Your issue is simply that .onChange(of:)
isn't a responder to the TextEditor
, it is a responder for the variable, in this case chatTextInput
. Since chatTextInput
is bound to the TextEditor
, when you type a letter, chatTextInput
is updated, and .onChange(of:)
runs. However, as part of .onChange(of:)
running, you change chatTextInput
which calls .onChange(of:) again. You would have an infinite loop, except that
.onChange(of:)` ends at this point. If anyone can explain that, I would love to hear it.
The fix, however is to simply put a flag in .onChange(of:)
to only set the variables every other time like this:
struct ChatView: View {
@State var chatTextInput: String = ""
@State var oldChatValue: String = ""
@State var newChatValue: String = ""
@State var textEntryFlag = true
var body: some View {
VStack {
TextEditor(text: $chatTextInput)
.onChange(of: chatTextInput) { newValue in
if textEntryFlag {
oldChatValue = "a"
newChatValue = newValue.last.map{String($0)}!
chatTextInput = oldChatValue
}
textEntryFlag.toggle()
}
}
}
}