RxSwift Reverse observable aka two way binding

Danny Lazarow
4 min readDec 25, 2018

--

When we hear Reactive programming we usually think about listeners of Observable sequences, transformers and combining data, and reacting on changes.

So.. RxSwift is about passing data from the business logic to views, right? but how about passing events in both directions

TextField <------> Observable <------> TextField
Auto Updating form fields

We’ll look at the following two use cases:

  • binding 2 textfields and subscribing to each other’s text control property (when change the text in one of them, the other automatically updates)
  • go next level and make first/last/full name form that updates like on the picture above

Let’s get started!

Existing libraries and approaches

Before starting out and coding I sometimes like to check if I did’n reinvent the hot water — do we have some existing libraries or something else done related to the topic.

RxBiBinding

And… I found this library

that does excellent job. I just have to to connect two textfields like so

and it will listen for changes in the textfields, and update textfields texts in both directions.

And it is good enough for the most simple use case - sending text between textFieldFirst and textFieldSecond and back as it is. This library does not provide a way to map and modify the passed sequence of Strings.

And in the real world we don’t pass observable sequences as it is, we often map/transform it (for example: if I would like to pass only numbers and filter out letters…)

RxSwift main repository examples folder.

The next approach I found was in the examples folder of RxSwift https://github.com/ReactiveX/RxSwift/blob/master/RxExample/RxExample/Operators.swift#L17

It binds the BehaviourRelay property and ControlPropery to each other, and it sends updates in both directions to properties as expected.

I was worried that it will cause loop (because of binding properties to each other)(relay send events to control property, and control property send the same to subscribed relay, then relay send to control property same event ….forever), but it appears that ControlProperty have built-in mechanism that stops event to not be emitted twice

-> BehaviourRelay -> ConrolProperty ----> X -----> BehaviourRelay

How does it work

When send send event on BehaviourRelay , ControlPropery updates because of the binding

When we send event on ControlPropery , BehaviourRelay updates because of the subscription

// value flow
trigger the state of control (e.g. `UITextField`) ->
ControlProperty emits event ->
value assigned to BehaviourRelay ->
BehaviourRelay emits event ->
ControlProperty receives event ->
value assigned to underlying control property (e.g. `text` for `UITextField`)

So a simple why there is no loop:

  • a value from a control is emitted once some kind of UIControlEvent is triggered
  • when a value is assigned directly to the control property, the control doesn’t trigger a change event so there’s no loop.

This approach satisfies our needs and we could modify text before subscribing the BehaviourRelay property.

Our Example

However the previous example won’t work well if we bind to each other two BehaviourRelay properties— it will cause event loop

-> textFirst BehaviourRelay -> textSecond BehaviourRelay -> textFirst BehaviourRelay -> textSecond BehaviourRelay -> textFirst BehaviourRelay -> textSecond BehaviourRelay .....

Apparently if BehaviourRelay does not have built-in way to stop passing same event to it’s subscribers over and over so we are going to build that mechanism.

Previous Observable value

I did this little convenience helper to get previous sequence values of Observable

I need this because I need to tell which Observable (TextField text) was changed

The example

I have two textfields and I’ll have to get the value from changed field (with old value != current) and update textfield that is unchanged (with old value == current)

And If I don’t want to cause forever loop I’ll have to check that the current values of the fields are equal, to stop propagating evens (filter RxSwift operator)

and then use it like that

Auto Updating form fields in both directions

More complex Example

This is the full code for two way binding between first and last and full name text fields (like on the animated gif on top)

When we enter text in textFirst and textSecond the lastname field (textFull) is updated with concatenated first and last name texts.

Link to the Example repository https://github.com/vaderdan/Example2WayBinding

--

--