Backbone: getting a view object from an element

Let's say I have some items to show in the list. The list has a view that combines all the items as items. Now I want to handle click events on item views and delegate processing to list view.

Check out the sample code:

ItemView = Backbone.View.extend({
    className: 'item',
    initialize: function() {
        this.$el.data('backbone-view', this);
    }
});

      

Note that I myself bind the view object as a property of the root element, which essentially creates a circular reference situation for the view and element.

ListView = Backbone.View.extend({
    initialize: function() {
        // contains the item views
        this.items = [];

        // click event delegation
        this.$el.click(_.bind(this._onClick, this));
    },

    addItem: function(v) {
        if ( !(v instanceof ItemView) ) return;

        this.items.push(v);
        this.$el.append(v.el);
    },

    _onClick: function(e) {
        var el = $(e.target).closest('.item'),
            view = el.data('backbone-view');

        // do something with the view
    }
});

      

This is a very common pattern whenever you have to deal with any kind of lists.

I am getting the representation of an element in a handler via a data property that I set on the element during initialization. I need to get the view of the element because everything I want to do for the element as part of handling the click event is view based.

Also note what I'm using closest

because the element's presentation can be tricky and the actual target of the click event may be a descendant of the root element.

So the question is, is this a way to bind a view to a root element via properties the data

right approach - especially when considering garbage collection and memory leaks? What could be better than this?

+3


source to share


1 answer


You have to catch events in the child view. In my opinion, any Backbone view should only handle DOM events of its element and its children. If the views are nested like yours, the most specific view is to handle events.

If you want to delegate processing to the parent view, you can fire the underlying event in ItemView

and listen to those in ListView

.



ItemView = Backbone.View.extend({
  events: {
    "click":"onClick"
  },
  onClick: function() {
    //trigger a custom event, passing the view as first argument
    this.trigger('click', this);
  }
});

ListView = Backbone.View.extend({
  addItem: function(v) {
    if ( !(v instanceof ItemView) ) return;
    //listen to custom event
    this.listenTo(v, 'click', this._onClick);
    this.items.push(v);
    this.$el.append(v.el);
  },
  _onClick:function(itemView) {
    //...
  }
});

      

If the event click

is some kind of "higher level" action, such as select

or activate

, you must name your own events as such. This way you can create a logical and reliable interface between your views without specifying a parent ListView

with the implementation details of its child. Only ItemView

needs to know if it was pressed, hung, double-clicked, etc.

+1


source







All Articles