Introduction to the Reactive Extensions for JavaScript – jQuery Integration

So far in this series, we’ve discussed the intent of the Reactive Extensions for JavaScript (RxJS) and how to create the publishers (Observables) and subscribers (Observers).  Along the way, we’ve talked a little about integration with other libraries such as jQuery (although we could talk about others) and since JavaScript developers tend to work in quite a few libraries, it’s best to see how we can fit RxJS in those solutions.

In the previous posts, I’ve shown jQuery in combination with RxJS to show how the two can play together.  For example, we can create a click handler on a single element with an ID of someElement.

var element = $("#someElement").get(0);
var observable = Rx.Observable.FromHtmlEvent(element, "click");

Unfortunately, that doesn’t take full advantage of the things jQuery can do for us, so I think we can do better.  in this post, let’s look at how we could further tie the two libraries together.

Before we get started, let’s get caught up to where we are today:

From jQuery Events to Observables

As I showed above, we could integrate using jQuery by only using a single element at a time with the get function.  But, that certainly doesn’t scale as it would only allow for single selectors, and that would miss out of the simplicity and beauty of the library.  What we really want to do is utilize the work that has already been done inside jQuery for event handling and extend it with RxJS.

Using jQuery we can bind to events with the bind function, which takes the event type, optional event data and a handler function.

$("#someElement").bind("click",  {msg: "hi"}, function() {
    alert("Clicked on someElement with " + event.data.msg);
});

What we want to do is extend this behavior to make these events composable.  For example, how about being able to take all spans and divs on a document and attach to the click event?  Inside the click event subscription, we want to get the pageX and pageY values and display them through an alert.

$(document).ready(function() {

    Rx.Observable.FromJQuery($("div, span"), "click")
        .Subscribe(function (event) {
        
        $("#baz").html("The mouse cursor is at ("
          + event.pageX + ", " + event.pageY + ")");
    });
});

Just as well, we could also take it a little bit further and bind to two events together, our mouseenter and mouseleave to toggle the highlight class on our div and span elements.

$(document).ready(function() {

    Rx.Observable.FromJQuery($("div, span"), "mouseenter mouseleave")
        .Subscribe(function (event) {
        
            $("div, span").toggleClass("highlight");
    });
    
});

In order to support this, the RxJS framework has provided a FromJQuery method onto the Observable class.  This function takes our jQuery object, our event type and any event data we have and we call the Create function to create an Observable.  Inside the Create function, we are handed an Observer which we used to yield the next value inside of the handler function.  We then bind the event type, our data and our handler to the jQuery object which then integrates RxJS and jQuery.  Finally, we return a function which is to be called when we need to clean up, and in this case, we unbind the handler from the event type.

Rx.Observable.FromJQuery = function(jQueryObject, eventType, eventData) {
    return Rx.Observable.Create (function(observer) {
        var handler = function(eventObject) {
            observer.OnNext(eventObject);
        };
        jQueryObject.bind(eventType, eventData, handler);
        return function() {
            jQueryObject.unbind(eventType, handler);
        };
    });
};

This is a great start, but why can’t we also just extend the jQuery object itself with a function called ToObservable which takes event type and event data.  In this example we can take the click and double click events from our div and span elements and then display the mouse cursor position.

$(document).ready(function() {
    
    $("div, span").ToObservable("dblclick click")
        .Subscribe(function(event) {
        
        $("#baz").html("The mouse cursor is at ("
          + event.pageX + ", " + event.pageY + ")");
    });      
});

To make this happen, RxJS will also provide a jQuery plugin which allows for this behavior.  This plugin does nothing more than call the RxJS FromJQuery method with the jQuery object, the event type and the event data.

jQuery.fn.ToObservable = function(eventType, eventData) {
    return Rx.Observable.FromJQuery(this, eventType, eventData);
}

What we get from these two pieces is that jQuery and RxJS can really talk together on a new level they hadn’t been able to before.  And this approach is certainly not restricted to just jQuery.  We could look at other libraries as well for integration points to see where it makes sense.

Conclusion

One of the important stories around the Reactive Extensions for JavaScript is the integration to your JavaScript library of choice, whether it be jQuery, Dojo, Ext, etc.  By providing this functionality out of the box to jQuery for example, it enables developers to freely move between the two libraries.

This of course is only scratching the surface of what capabilities this library has and there is much more yet left to cover.  The question you’re probably asking now is where can I get it?  Well, for that you’ll have to stay tuned.  I hope to have more announcements soon about its general availability.

What can I say?  I love JavaScript and very much looking forward to the upcoming JSConf 2010 here in Washington, DC where the Reactive Extensions for JavaScript will be shown in its full glory with Jeffrey Van Gogh (who you can now follow on Twitter).  For too many times, we’ve looked for the abstractions over the natural language of the web (HTML, CSS and JavaScript) and created monstrosities instead of embracing the web for what it is.  With libraries such as jQuery and indeed the Reactive Extensions for JavaScript gives us better tools for dealing with the troubled child that is DOM manipulation and especially events.

This entry was posted in Event-based Porgramming, JavaScript, JSConf, Reactive Framework. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Atanas,

    Right, and that’s feedback for the team. Right now they were doing it to keep parity with the .NET version, but ultimately, it should fit in with the language.

    Matt

  • Atanas Korchev

    How about using the JavaScript naming convention? Currently using the Rx feels more like C# not JavaScript.
    For starters you can change the method to be camel-cased.

  • http://blog.calyptus.eu/ Sebastian Markbåge
  • http://www.javascriptbank.com/ JavascriptBank.com

    very cool & good tip, thank you very much for sharing.

    Can I share this post on my JavaScript library?

    Awaiting your response. Thank