RxSwift Reverse observable aka two way binding
Tags: swift, rxswift, reactive, ios
Published: 2018-12-27 15:35:27

---
layout: post
tags: swift, RxSwift, Reactive, iOS
title: RxSwift Reverse observable aka two way binding
cover_image: https://cdn-images-1.medium.com/max/800/1*30nP0TSNK7MCcQc7j57V6w.png
description: RxSwift Two way Binding- When property changed, it will notify variable, and set the variable's value, while the variable's value is set, it will notify the property (how to evade endless loop)
published: true
---

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
```

![](https://cdn-images-1.medium.com/max/800/1*jUoFEq2ZB7u5YcpapuhT_g.gif)



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 text 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

[**RxSwiftCommunity/RxBiBinding** ](https://github.com/RxSwiftCommunity/RxBiBinding "https://github.com/RxSwiftCommunity/RxBiBinding")

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

```swift
import RxBiBinding

let disposeBag = DisposeBag()

var textFieldFirst = UITextField()
var textFieldSecond = UITextField()

(textFieldFirst.rx.text <-> textFieldSecond.rx.text).disposed(by: disposeBag)
```

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](https://github.com/ReactiveX/RxSwift/blob/master/RxExample/RxExample/Operators.swift#L17)

```swift
// Two way binding operator between control property and relay, that's all it takes.
infix operator <-> : DefaultPrecedence

func <-> (property: ControlProperty, relay: BehaviorRelay) -> Disposable {
    let bindToUIDisposable = relay.bind(to: property)
    let bindToRelay = property
        .subscribe(onNext: { n in
            relay.accept(n)
        }, onCompleted:  {
            bindToUIDisposable.dispose()
        })

    return Disposables.create(bindToUIDisposable, bindToRelay)
}
```

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

```swift
let bindToUIDisposable = relay.bind(to: property)
```

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

```swift
let bindToRelay = property
        .subscribe(onNext: { n in
            relay.accept(n)
        }, onCompleted:  {
            bindToUIDisposable.dispose()
        })
```

```
// value flowtrigger 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` — it will cause event loop

```swift
let textFirst = BehaviorRelay(value: nil)
let textSecond = BehaviorRelay(value: nil)

(textSecond <-> textFirst).disposed(by: disposeBag)
```

```
-> 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

```swift
extension ObservableType {
  func currentAndPrevious() -> Observable<(current: E, previous: E)> {
    return self.multicast({ () -> PublishSubject in PublishSubject() }) { (values: Observable) -> Observable<(current: E, previous: E)> in
      let pastValues = Observable.merge(values.take(1), values)
      
      return Observable.combineLatest(values.asObservable(), pastValues) { (current, previous) in
        return (current: current, previous: previous)
      }
    }
  }
}
```

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)

```swift
infix operator <->

func <-> (lhs: BehaviorRelay, rhs: BehaviorRelay) -> Disposable {
    typealias ItemType = (current: T, previous: T)
    
    return Observable.combineLatest(lhs.currentAndPrevious(), rhs.currentAndPrevious())
        .filter({ (first: ItemType, second: ItemType) -> Bool in
            return first.current != second.current
        })
        .subscribe(onNext: { (first: ItemType, second: ItemType) in
            if first.current != first.previous {
                rhs.accept(first.current)
            }
            else if (second.current != second.previous) {
                lhs.accept(second.current)
            }
        })
}
```

and then use it like that

```swift
let textFirst = BehaviorRelay(value: nil)
let textSecond = BehaviorRelay(value: nil)
(textSecond <-> textFirst).disposed(by: disposeBag)
```

![](https://cdn-images-1.medium.com/max/800/1*jUoFEq2ZB7u5YcpapuhT_g.gif)


### 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.

![](https://cdn-images-1.medium.com/max/800/1*no78U4UR4zE0FLhw8inN2A.gif)

```swift
let textFull = BehaviorRelay(value: nil)
let textFirst = BehaviorRelay(value: nil)
let textSecond = BehaviorRelay(value: nil)
    
    
typealias ItemType = (current: String, previous: String)

Observable.combineLatest(textFirst.map({ $0 ?? "" }).currentAndPrevious(), textSecond.map({ $0 ?? "" }).currentAndPrevious(), textFull.map({ $0 ?? "" }).currentAndPrevious())
      .filter({ (first: ItemType, second: ItemType, full: ItemType) -> Bool in
        return "\(first.current) \(second.current)" != full.current && "\(first.current)" != full.current
      })
      .subscribe(onNext: { (first: ItemType, second: ItemType, full: ItemType) in
        if first.current != first.previous || second.current != second.previous {
          textFull.accept("\(first.current) \(second.current)")
        }
        else if (full.current != full.previous) {
          let items = full.current.components(separatedBy: " ")
          let firstName = items.count > 0 ? items[0] : ""
          let lastName = items.count > 1 ? items[1] : ""

          if firstName != first.current {
            textFirst.accept(firstName)
          } else if lastName != second.current {
            textSecond.accept(lastName)
          }
        }
      })
      .disposed(by: disposeBag)


(textFieldFirst.rx.text <-> textFirst).disposed(by: disposeBag)
(textFieldSecond.rx.text <-> textSecond).disposed(by: disposeBag)
(textFieldFull.rx.text <-> textFull).disposed(by: disposeBag)
```

Link to the Example repository

[https://github.com/vaderdan/Example2WayBinding](https://github.com/vaderdan/Example2WayBinding)