Search code examples
javascriptjquerybackbone.js

Backbone remove events from previous view


I have a trouble probably caused from lack of understanding Backbone's event mechanism.

Either I get previous events still attached or current events not firing.

  1. If I don't use $('body').off() or this.$el.off() (my target is body) obviously everything remains because Backbone's event model attaches & listens to what's propagated on body.

  2. If I use $('body').off() or this.$el.off(), in initialize method, like this:

    module.exports = Backbone.View.extend({
        initialize: function(){
            this.KontaktViewTemplate = $.ajax({ url:'index.php/templateget/kontakt', dataType:'text', cache:true});
            this.$el.off();
            this.render();
        },
        render: function(){
            var $el = this.$el;
            this.KontaktViewTemplate.done(function(text){
                $el.html(text);
            });
        },
        events: {
            'click div': "Alert"
        },
        Alert: function(){
            alert('Example');
        }
    });
    

I even don't get 'click div': "Alert" to work.

My best guess that events from Backbone's View are attached even before initialize method is called, thus .off() call comes too late and wipes them out.

Should I handle this outside of Backbone?


Solution

  • Backbone View's events are just namespaced jQuery events (source).

    delegate: function(eventName, selector, listener) {
      this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
      return this;
    },
    

    They are delegated inside the setElement function (source) which is called in _ensureElement before initialize in the View's constructor.

    If an element is shared with multiple Backbone Views, or if you reuse the same view in multiple place, you could be having problems with the events still attached or doubled.

    Say your view is a bare div like the default and you want it to use the existing element <div id="existing"></div> and that div already has events attached to it.

    You'll do something like:

    view.setElement($('#existing'));
    

    setElement will first undelegate events from the view only. Any events attached elsewhere will still be attached. Then, it delegates events from the events view property.

    Also, calling remove (source) on a view will explicitly undelegate any events attached to the element.