I would like to have a UITextField configured with RxSwift/RxCocoa so that it only contains up to ... characters. I do not want to use the UITextFieldDelegate
for this but would love to achieve this with RxSwift/RxCocoa. Is there a way to do this?
Asked
Active
Viewed 9,021 times
19

swalkner
- 16,679
- 31
- 123
- 210
1 Answers
39
Sure:
textField.rx.controlEvent(.editingChanged).subscribe(onNext: { [unowned self] in
if let text = self.textField.text {
self.textField.text = String(text.prefix(40))
}
}).disposed(by: disposeBag)
In this example, the textfield is limited to 40 characters.
Edit:
Keeping the previous value when the limit is reached.
textField.rx.text.orEmpty
.scan("") { (previous, new) -> String in
if new.count > 40 {
return previous ?? String(new.prefix(40))
} else {
return new
}
}
.subscribe(textField.rx.text)
.disposed(by: disposeBag)
This can probably be adapted to respect other rules...
Please note however that when reaching the character limit, your cursor will jump to the end of the textField.

Valérian
- 1,068
- 8
- 10
-
That's close, but not exactly what I'm looking for. E.g. if the text field has 40 characters and the user types a character at the beginning I would like to prevent that and let the content unchanged, in your case the new character is taken and the last one disappears. – swalkner Feb 14 '18 at 21:42
-
Edited my post to answer your extra criteria. Hope this helps. – Valérian Feb 14 '18 at 22:18
-
@Valérian for your edited answer, the `String(new.prefix(40))` in `return previous ?? String(new.prefix(40))` will never execute, the `previous` value will never be nil so why you are adding it? – mojtaba al moussawi Sep 04 '18 at 08:45
-
Unfortunately, the compiler makes previous optional because `textField.rx.text` expects an optional string. You can get rid of this by adding `.map { Optional($0) }` between `scan` and `subscribe`. – Valérian Sep 04 '18 at 09:28
-
@Valérian `previous` isn't optional and it will never be! What i meant is that there is no meaning for `String(new.prefix(40))` and it will never be executed since previous isn't optional ,You have make it non optional by seeding the `Scan` with empty string `scan("")`... – mojtaba al moussawi Sep 04 '18 at 10:26
-
While I agree with you in theory, using the above code in my project, the compiler considers it as optional when it shouldn't. Have you tried on your side ? – Valérian Sep 04 '18 at 11:44
-
Yes @Valérian , mine it considers it as non-optional. – mojtaba al moussawi Sep 04 '18 at 11:52
-
How to get UITextfield's typing character in Rxswift ? Can anyone help me? – McDonal_11 Nov 11 '19 at 04:14
-
@Valérian For example the textfield is initially blank and then the limit is 2 chars. If programmatically I set the value like this: textfield.text = "123". Textfield will still be blank. How can it get "12" instead? – iadcialim24 Jan 04 '20 at 05:52
-
Setting the text like you mention doesn't trigger a control event so you probably have something else going on. You can add debug operators in the sequence to confirm that. – Valérian Jan 06 '20 at 09:32
-
True. `.scan("") { previous, new in (new.count > 40) ? previous : new }` is enough. – SoftDesigner Dec 30 '20 at 17:16