0

I'm making a Backbone.js app and it includes an index view and several subviews based on id. All of the views have been bound with mousedown and mouseup events. But every time I go from a subview to the index view and then go to any of subviews again, the mousedown and mouseup events in the current subview will be triggered one more time, which means when I click the subview, there will be several consecutive mousedown events triggered followed by several consecutive mouseup events triggered.

After looking through my code, I finally found that it's the router that causes this problem. Part of my code is as follows:

    routes: {
        "": "index",
        "category/:id": "hashcategory"  
    },

    initialize: function(options){
        this._categories = new CategoriesCollection();
        this._index = new CategoriesView({collection: this._categories});

    },

    index: function(){
        this._categories.fetch();
    },

    hashcategory: function(id){
        this._todos = new TodosCollection();
        this._subtodolist = new TodosView({ collection: this._todos, 
                                            id: id                                              
                                         });
        this._todos.fetch();
   }

As you can see, I create the index collection and view in the initialize method of the router, but I create the subview collection and view in the corresponding route function of the router. And I tried to put the index collection and view in the index function and the click event in index view will behave the same way as subviews. So I think that's why the mousedown and mouseup will be triggered several times.

But the problem is, I have to use the id as one of the parameters sent to subview. So I can't create subview in the initialize method. What's more, I've already seen someone else's projects based on Backbone and some of them also create sub collection and view in the corresponding route function, but their app runs perfectly. So I don't know what is the root of my problem. Could someone give me some idea on this?

4

1 に答える 1

1

Sounds like you're having a delegate problem because:

all sub views all use the a same <div> element

Backbone views bind to events using jQuery's delegate on their el. If you have a view using a <div> as its el and then you use that same <div> for another view by replacing the contained HTML, then you'll end up with both views attached to that <div> through two different delegate calls. If you swap views again, you'll have three views receiving events through three delegates.

For example, suppose we have this HTML:

<div id="view-goes-here"></div>

and these views:

var V0 = Backbone.View.extend({
    events: { 'click button': 'do_things' },
    render: function() { this.$el.html('<button>V0 Button</button>'); return this },
    do_things: function() { console.log('V0 clicked') }
});        
var V1 = Backbone.View.extend({
    events: { 'click button': 'do_things' },
    render: function() { this.$el.html('<button>V1 Button</button>'); return this },
    do_things: function() { console.log(V1 clicked') }
});

and we switch between them with something like this (where which starts at 0 of course):

which = (which + 1) % 2;
var v = which == 0
      ? new V0({el: $('#view-goes-here') })
      : new V1({el: $('#view-goes-here') });
v.render();

Then you'll have the multi-delegate problem I described above and this behavior seems to match the symptoms you're describing.

Here's a demo to make it easy to see: http://jsfiddle.net/ambiguous/AtvWJ/

A quick and easy way around this problem is to call undelegateEvents on the current view before rendering the new one:

which = (which + 1) % 2;
if(current)
    current.undelegateEvents(); // This detaches the `delegate` on #view-goes-here
current = which == 0
      ? new V0({el: $('#view-goes-here') })
      : new V1({el: $('#view-goes-here') });
current.render();

Demo: http://jsfiddle.net/ambiguous/HazzN/

A better approach would be to give each view its own distinct el so that everything (including the delegate bindings) would go away when you replaced the HTML. You might end up with a lot of <div><div>real stuff</div></div> structures but that's not worth worrying about.

于 2012-05-03T03:28:18.910 に答える