Using DidSet on array of Strings to have character limit doesn't work

Viewed 76

I am trying to create a character limit for a TextField which corresponds to a String within an array with the following code but it doesn't seem to work. The following object is a poll object where the user can add TextFields in which they can write in the option they desire. I'm trying to build a max character limit for each string in which if a TextField exceed the value of the max character limit, the array of Strings (or the violating string) is replaced with the old value. Right now, the print statements indicate that the values are being updated and fixed at the max character limit, but on the View, I can still type beyond the max character limit which is odd since the value in the TextField should be bound to the published variable.

VStack {
    ForEach(0..<newPollVM.pollOptions.count, id: \.self) { i in
        HStack {
            TextField("Option \(i + 1)", text: $newPollVM.pollOptions[i])
            .font(.title3)
            .padding(5)
            .overlay(RoundedRectangle(cornerRadius: 5).stroke(Color(UIColor.systemGray), lineWidth: 2))
                    
            Spacer()
                    
            if newPollVM.pollOptions.count > 2 {
                Button {
                    print("DEBUG: Remove row")
                    newPollVM.pollOptions.remove(at: i)
                 } label: {
                    Image(systemName: "delete.left")
                    .foregroundColor(.red)
            }
        }
    }
    .padding(.top, 5)
}
            
if newPollVM.pollOptions.count < 6 {
    Button {
        print("DEBUG: Add Option")
        newPollVM.pollOptions.append("")
        print("DEBUG: \(newPollVM.pollOptions)")
    } label: {
        Text("Add")
        .foregroundColor(.green)
    }
}
class NewPollViewModel: ObservableObject {
    let characterLimit = 5
    @Published var allowSkipVoting : Bool = false
    @Published var pollOptions : [String] = [""] {
        didSet {
            for (index, pollOption) in pollOptions.enumerated() {
                if pollOption.count > characterLimit && oldValue[index].count <= characterLimit {
                    print("DEBUG: \(oldValue)")
                    self.pollOptions[index] = oldValue[index]
                    print("DEBUG: \(pollOptions)")
                }
            }
        }
    }
    
    func reset() {
        self.allowSkipVoting = false
        self.pollOptions = ["", ""]
    }
}

However, the following code works regarding setting a character limit for a single String.

TextArea("What's on your mind?", text: $newPostVM.title)
    .font(.title)
class NewPostViewModel: ObservableObject {
    let characterLimit = 180
    @Published var title : String = "" {
        didSet {
            if title.count > characterLimit && oldValue.count <= characterLimit {
                title = oldValue
            }
        }
    }
}
1 Answers

This isn't what you asked for exactly. But I think it solves your problem in a better way. You can just use the limit field on your UITextField. Something like...

yourTextField.textLimit(existingText: textField.text,
                          newText: string,
                          limit: 180)

Here is a helpful link that shows a good way to do it.

Related