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.
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();
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.
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));
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
});
});
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();