-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Japanese text would be broken if UITextField has two-way-binding ControlProperty and Variable. #649
Comments
I am a japanese developer also faced same problem. extension ControlProperty {
func cyclePrevented() -> ControlProperty<PropertyType> {
var fromControl = false
let observable = Observable<PropertyType>.create { observer in
let sub = self.subscribe { ev in
fromControl = true
observer.on(ev)
fromControl = false
}
return sub
}
let observer = AnyObserver<PropertyType> { ev in
if !fromControl {
self.on(ev)
}
}
return ControlProperty(values: observable, valueSink: observer)
}
}
user.name <-> userNameField.rx_text.cyclePrevented() |
Hi, guys Looks like this is related to #626 I removed |
Thank you @omochi @sergdort @kzaher But this problem would occur in latest master branch still...
For example, I explain the case of I input "あ" in In this case, we input "あ" first, then I think @omochi 's extension is work well, but there is no check the event is realy from ownself. |
I try to explain more detail of @tarunon said. So his scenario is able to written as below. First state. @tarunon Is my understanding same to you? |
@omochi @Succete |
@Succete Thank you for a suggestive report. |
I think I know how to solve it. It's not the two way binding that need to be changed. this is the problem
then it's correct
|
Hi guys, That's an interesting discussion for sure :) It seems to me that adding something like /**
Reactive wrapper for `text` property. Notifications are fired only when when there
isn't any marked text.
*/
public var rx_nonMarkedText: ControlProperty<String> {
let textProperty = self.rx_text
return ControlProperty(
values: textProperty._values.filter { [weak self] _ in self?.markedTextRange == nil },
valueSink: textProperty._valueSink
)
} let textValue = Variable("")
textField.rx_nonMarkedText <-> textValue
textValue.asObservable()
.subscribeNext { [weak self] x in
self?.debug("UITextField text \(x)")
}
.addDisposableTo(disposeBag) would solve your problems. I don't understand the full culture/language context so if you could provide feedback, that would be great. |
Hi @kzaher , it's great. |
Hi @kzaher I think the best of solve this problem is using properly |
Hi @tarunon @Succete @omochi , yeah I was thinking of having two properties. Both for The other one being
so if we did that, would that make sense and solve all issues? |
Hi @kzaher , |
Hi @kzaher , /**
Reactive wrapper for `text` property.
*/
private var rx_textInternal: ControlProperty<String> {
return UIControl.rx_value(
self,
getter: { textField in
textField.text ?? ""
}, setter: { textField, value in
textField.text = value
}
)
}
/**
Reactive wrapper for `text` property. Notifications are fired only when when there
isn't any marked text.
*/
public var rx_text: ControlProperty<String> {
let textProperty = self.rx_textInternal
return ControlProperty(
values: textProperty._values.filter { [weak self] _ in self?.markedTextRange == nil },
valueSink: textProperty._valueSink
)
}
/**
Reactive wrapper for `text` property. Notifications are fired only when when there
is marked text.
*/
public var rx_markedText: ControlProperty<String> {
let textProperty = self.rx_textInternal
return ControlProperty(
values: textProperty._values.filter { [weak self] _ in self?.markedTextRange != nil },
valueSink: textProperty._valueSink
)
} I think we satisfy using |
@tarunon @kzaher |
@omochi Sorry I misunderstood |
Hi guys, I'm still thinking how to best handle this. What ever solution I come up with, it has it's drawbacks. Any solution is this form
I've thought about solutions in this form
Then I've thought about solutions in this form
Then I thought, well ok, why don't we just do
My suggestion would be ... I'm not too happy with what I'm about to say, but wouldn't it make sense if we would just add that convenience in front of protocol RxTextInput {
var rx_text: ControlProperty<String> { get }
}
extension UITextField : RxTextInput {
}
extension UITextView: RxTextInput {
}
extension RxTextInput {
/**
Reactive wrapper for `text` property. Notifications are fired only when when there
isn't any marked text.
*/
public var rx_nonMarkedText: ControlProperty<String> {
let textProperty = self.rx_text
return ControlProperty(
values: textProperty.asObservable().filter { [weak self] _ in self?.markedTextRange == nil },
valueSink: textProperty.asObserver()
)
}
}
// Two way binding operator between control property and variable, that's all it takes (well, almost) {
infix operator <-> {
}
func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable {
let bindToUIDisposable = variable.asObservable()
.bindTo(property)
let bindToVariable = property
.subscribe(onNext: { n in
variable.value = n
}, onCompleted: {
bindToUIDisposable.dispose()
})
return StableCompositeDisposable.create(bindToUIDisposable, bindToVariable)
}
// } We don't bundle that What we could include in the protocol RxTextInput {
var rx_text: ControlProperty<String> { get }
}
extension UITextField : RxTextInput {
}
extension UITextView: RxTextInput {
} so you would just need to write extension RxTextInput {
/**
Reactive wrapper for `text` property. Notifications are fired only when when there
isn't any marked text.
*/
public var rx_nonMarkedText: ControlProperty<String> {
let textProperty = self.rx_text
return ControlProperty(
values: textProperty.asObservable().filter { [weak self] _ in self?.markedTextRange == nil },
valueSink: textProperty.asObserver()
)
}
}
// Two way binding operator between control property and variable, that's all it takes (well, almost) {
infix operator <-> {
}
func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable {
let bindToUIDisposable = variable.asObservable()
.bindTo(property)
let bindToVariable = property
.subscribe(onNext: { n in
variable.value = n
}, onCompleted: {
bindToUIDisposable.dispose()
})
return StableCompositeDisposable.create(bindToUIDisposable, bindToVariable)
}
// } |
There are 2 major problems. First, Japanese developers need to handle this issue. Second, Japanese user of application made with RxSwift by Non-Japanese developers can not use it correctly. Sorry for my lack of best solution proposal and many negative comments. |
Hi @omochi , Thnx for expressing your concerns. I think you are right and we haven't considered problem 2 sufficiently. Yes, it looks like not only Japanese developers need to take care of that, but all developers. Because if you have app built in Croatia that some Japanese user is using with that type of keyboard, it will fail for them also. We also agree that I would like to improve situation regarding IME methods. I don't think that we can change behavior of
I think there are two different problems that we should answer.
I don't currently see any way how to solve these two points with any solution, no matter how complex. What I was maybe thinking of doing is:
I'm not sure it is possible for us to control what people write on the internet, or create an API so that how ever people use it, it just works in all cases. I'm open to suggestions as always, but currently I don't see how we can solve this in the |
This should work for second part of the problem :)
|
…always setting the text value even when the value was equal, and thus clearing the marked text state. #649
…always setting the text value even when the value was equal, and thus clearing the marked text state. #649
Changes that fix this problem have been release. Feel free to reopen this issue if needed. |
# By Krunoslav Zaher (23) and others # Via Krunoslav Zaher * 'master' of https://github.com/ReactiveX/RxSwift: (72 commits) Improves unit tests. Updates RxDataSources. Changes 2.5 to 2.5.0. Adds 2.5.0 changes to CHANGELOG. Makes `NSTextField` implement `RxTextInput`. Fixes Wikipedia automation tests. Improves delegate proxy messaging. ReactiveX#675 Turns off bitcode for RxTests. ReactiveX#584 Release 2.5 More comprensible `ActivityIndicator` Improve language in comment Use new Swift selector syntax in comment Update comment to use new non-deprecated method Fix argument key in comment Typo in comment 'extensions' with an 's' Improves documentation for `DelegateProxy.observe`. ReactiveX#654 Adds unit test for only setting different text values. Provides explanations for check. Fixes problems with two way binding that was caused by `rx_text` and always setting the text value even when the value was equal, and thus clearing the marked text state. ReactiveX#649 Add missing Next link ...
Hey there guys, I have the same issue when binding to a BehaviourRelay. The Japanese highlighting stops working. let value: BehaviorRelay<String> = .init(value: "")
self.textField.textField?.rx.text.orEmpty
.bind(to: self.value)
.disposed(by: self.disposeBag)
//same for this
self.textField.textField?.rx.text.orEmpty.asDriver()
.drive(onNext: { (value) in
self.value.accept(value)
})
.disposed(by: disposeBag) |
I use two-way-binding operator
UITextField.rx_text
andVariable
like RxExample.https://github.com/ReactiveX/RxSwift/blob/master/RxExample/RxExample/Examples/APIWrappers/APIWrappersViewController.swift#L142-L149
And please see this capture.

I want to input "あいうえお" at the
textField
, but we can see a wrong text "ああいあいうあいうえあいうえお".I believe
ControlProperty
should not receive event about the value inputted from user, becausetextField
would lost the invisible state when set the same text.And
UITextView
has the nearly same problem.In
UITextView
, we cannot use IME character conversion.This problem would occur in every language that has IME.
I believe the easy way to solve this problem is change the implements of two-way-binding operator.
But... I think
ControlProperty
(orrx_value
) might check the observed value is not equal to a value inputted from user.The text was updated successfully, but these errors were encountered: