LiftWeb makes building dynamic websites extremely easy whilst hiding away a lot of the plumbing. RxScala is a Scala adaptor for RxJava, “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”.
This blog describes how we combined Lift and RxScala for event-based UI components consuming and producing observable sequences.
The original motivation for combining Rx and Lift was simply as an experiment - could we treat UI components as sources and sinks of Observable streams of values.
The idea proved to be quite successful, particularly when the backend system is built with Rx so there is no impedance mismatch. We ended up using these ideas for a greenfield project in a large financial institution in London.
Finally, point your browser at http://127.0.0.1:8080 to try out the examples.
The Basic Ideas
There are several fundamental ideas illustrated in the following figure:
- SHtml is Lift’s library for building UI components on which RxElement is built
- an Observable stream of values,
- AJAX updates from the client are mapped into an Observable stream of values
The are two fundamental data types:
RxComponent wraps a function that accepts an
Observable[T] and returns an
RxElement[O]. It will become clear why this is necessary later but for now think of it as a function for building an
RxElement given an
RxElement.values is the output stream of values, the
jscmd is the stream of Lift
ui is the HTML to bind into templates as usual in Lift.
To send the JsCmds emitted by
RxElement.jscmd to the browser, each
JsCmd needs to be sent to a comet actor that forwards it to the client.
The simplest example to start with is a text label since it maps an
Observable[String] to a stream of values pushed to the browser.
That’s it! The two lines of interest are the construction of
timeLabel and the call to
publish, the rest is vanilla RxScala or Lift.
Components is a collection of reusable UI components I’ve supplied, and publish is a method available via
An Input Element
The label above doesn’t emit anything so here is an example of an input element, whose values are emitted as an
To get values from the input field, subscribe to
in.values which is an
So far we can build UIs for simple streams of values. How can we build a reusable UI component for an
Observable of some richer structure?
The solution we opted for was to use Scalaz
Lens. The input
Observable is mapped to
Observables for each field with a set of lenses. But the complication is how to apply values emitted by each field’s component to the original data. The set of
Observable values need to be combined in some way to effect a change on the original value.
We addressed this by mapping each field’s
Observable to an
T is the type of the composite datatype (an
Endo wraps a function of
T => T). The set of
Observable[Endo[T]] for each field can be merged and applied to the original datatype.
The resulting component’s type is
I think this is one of those cases where code speaks louder than explanations.
Here is a model and an
RxComponent for the model.
The interesting code here is the focus method from RxLift’s
Components.scala. It applies a
Lens[T, F] to an
RxComponent[F, F] producing an
RxComponent[T, Endo[T]], which brings us back to why
RxComponent is needed.
RxElement is the result of applying an
Observable to an
RxComponent, so it is not possible to modify its input after construction.
RxComponents allow us to map and transform
Observables before their
RxElement is produced.
The last line,
fn + ln, combines each field into a
RxComponent[Person, Endo[Person]] by merging the
Observable streams of
ln, and joining the UI
Consequently, a change in any field will result in an
Endo[T] being emitted and so multiple updates to a datatype by different users will be safe. One user’s update will not overwrite anothers unless the same field is modified simultaneously by two or more users.
Here is a UI that uses the component.
BehaviourSubject is a subject that emits the most recent item it has observed and all subsequent observed items to each subscribed
Building reactive UI components based on RxScala and Lift has proven to be fairly straightforward. RxLift is an example project illustrating the basic ideas which have been used to build a fairly sophisticated UI in a large financial institution in London.