How do I work with jQuery and RxJS

The jQuery project and RxJS play very well together as libraries. In fact, we supply bindings directly for RxJS to jQuery should you want to wrap animations, events, Ajax calls and more using Observables in RxJS-jQuery. The bindings library provides many handy features for bridging the world to Observables. If you're interested in that library, go ahead and use it.

Using RxJS with Rx-jQuery

Getting started with the bindings is easy. Each method is enumerated on the main page from the jQuery method to its RxJS counterpart.

<div id="results"></div>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="rx.js"></script>
<script src="rx.binding.js"></script>
<script src="rx.jquery.js"></script>

Now we can start using the bindings! For example, we can listen to a click event and then by using flatMap or selectMap we can animate by calling animateAsObservable. Finally, we can subscribe to cause the side effect and nothing more.

$( "#go" ).clickAsObservable().flatMap(() => {

    return $( "#block" ).animateAsObservable({
        width: "70%",
        opacity: 0.4,
        marginLeft: "0.6in",
        fontSize: "3em",
        borderWidth: "10px"
    }, 1500 );
}).subscribe();

Using RxJS with jQuery

Let's start though by assuming you just have RxJS and wanted to get started with jQuery without the bridge library. There is already plenty you can do without even needing a bridge library with the support built in for events and promises.

Binding to an event

Using RxJS with jQuery to bind to an event using plain old RxJS is easy. For example, we could bind to the mousemove event from the DOM document easily.

First, we'll reference the files we need.

<div id="results"></div>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="rx.js"></script>
<script src="rx.async.js"></script>
<script src="rx.binding.js"></script>
var observable = Rx.Observable.fromEvent(
    $(document),
    'mousemove');

var subscription = observable.subscribe(e => $('#results').text(e.clientX + ',' + e.clientY));

We could go a step further and create our own jQuery plugin which handles events with ease.

/**
 * Creates an observable sequence by adding an event listener to the matching jQuery element
 *
 * @param {String} eventName The event name to attach the observable sequence.
 * @param {Function} [selector] A selector which takes the arguments from the event handler to produce a single item to yield on next.
 * @returns {Observable} An observable sequence of events from the specified element and the specified event.
 */
jQuery.fn.toObservable = function (eventName, selector) {
    return Rx.Observable.fromEvent(this, eventName, selector);    
};

Now we could rewrite our above example such as this.

var observable = $(document).toObservable('mousemove');

var subscription = observable.subscribe(e => $('#results').text(e.clientX + ',' + e.clientY));

Using RxJS with Ajax calls

Bridging to jQuery Ajax calls using $.ajax is easy as well with the built-in Promises A+ support. Since jQuery 1.5, the $.ajax method has implemented a promise interface (even if not 100% pure) which allows us to bridge to an observable sequence via the Rx.Observable.fromPromise method.

For example, we could query Wikipedia by calling the $.ajax method and then calling the promise method which then exposes the minimum promise interface needed.

function searchWikipedia (term) {
    var promise = $.ajax({
        url: 'http://en.wikipedia.org/w/api.php',
        dataType: 'jsonp',
        data: {
            action: 'opensearch',
            format: 'json',
            search: encodeURI(term)
        }
    }).promise();
    return Rx.Observable.fromPromise(promise);
}

Once we created the wrapper, we can query the service by getting the text and then using flatMapLatest to ensure we have no out of order results.

$('#input').toObservable('keyup')
    .map(e => e.target.value;)
    .flatMapLatest(searchWikipedia)
    .subscribe(data => {

        var results = data[1];

        $.each(results, (_, result) => {
            // Do something with each result
        });

    });

Using RxJS with Callbacks to Handle Simple Animations

RxJS can also be used to bind to simple callbacks, such as the .animate() method. We can use Rx.Observable.fromCallback to supply the required arguments with the last argument is to be the callback. In this example, we'll take the animation example from above and use nothing but core RxJS to accomplish the same thing.

You'll note that we need a notion of this for the block.animate to properly work, so we have two choices, either use Function.prototype.bind available in most modern browsers...

var animate = Rx.Observable.fromCallback(block.animate.bind(block));

Or we can supply an optional argument which supplies the context to the callback such as the following...

var animate = Rx.Observable.fromCallback(
    block.animate,
    null, /* default scheduler used */
    block /* context */);

When viewed in its entirety, it will look like this where we call flatMap or selectMany to compose together two observable sequences. We then bind to the animate function through Rx.Observable.fromCallback and then return the observable which results from the function execution. Our subscribe does nothing in this case as there is nothing to print or do, and is simply a side effect.

var block = $('#block');

$('#go').toObservable('click').flatMap(() => {
    var animate = Rx.Observable.fromCallback(block.animate.bind(block));

    return animate({
        width: "70%",
        opacity: 0.4,
        marginLeft: "0.6in",
        fontSize: "3em",
        borderWidth: "10px"
    }, 1500);
}).subscribe();