Search code examples
backbone.jsrxjs

Binding/Unbiding backbonejs events into RxJS


I am trying RxJS with my backbone project. Currently I have backbone styled events in view such as

events:{
    "click .cross_10_10":"clearSearch",
    "keypress .searchUsers": "searchUsers"
}

Backbone handles binding/unbinding these events appropriately. How can I use Rx.Observable.fromEvent/Rx.Observable.fromEventPattern to bind these events which also gets unbind when view disappears.

GitHub docs says RxJS supports hooks into backbone but could not find out how.

Current code

MyView = Backbone.View.extend({
    constructor: function(container) {
      var html = $.trim($("script#tmpl_myview").html());
      this.el = $(_.template(html)({type:"random"}));
    },
    events:{
      "keypress .searchUsers": "searchUsers"
    },
    searchUsers: function() {
       var searchTerm = this.$(".searchUsers").val().trim();
       $.get("/searchUsers?q="+searchTerm)
       .then(_.bind(this.drawUsers, this));
    },
    drawUsers: function(users) {
       //render users in dom
    }
})

I want to user RxJS to throttle search queries. If it was just jquery, not backbone, I would do this.

var keyStream = Rx.Observable.fromEvent($(".searchUsers"), 'keypress').debounce(300)
.map(function(e){
    return $(".searchUsers").val();
}).distinctUntilChanged();
var respStream = keyStream.switchMap(function(searchTerm){
    return $.get("/searchUsers?q="+searchTerm);
});
respStream.subscribe(function(users){
//render
});

I want to combine both and use best of these.


Solution

  • Below is the code for registering DOM events based on view's event hash:

     delegateEvents: function(events) {
      events || (events = _.result(this, 'events'));
      if (!events) return this;
      this.undelegateEvents();
      for (var key in events) {
        var method = events[key];
        if (!_.isFunction(method)) method = this[method];
        if (!method) continue;
        var match = key.match(delegateEventSplitter);
        this.delegate(match[1], match[2], _.bind(method, this));
      }
      return this;
    },
    delegate: function(eventName, selector, listener) {
      this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
      return this;
    },
    undelegateEvents: function() {
      if (this.$el) this.$el.off('.delegateEvents' + this.cid);
      return this;
    },
    

    delegateEvents is called while view is constructed and undelegateEvents is invoked internally by view's remove. You can override delegateEvents and undelegateEvents methods to add and remove your RxJS functionality for a specific view, or a base view that all your views extend from.