Backbone DOM events firing multiple times


Hi guys I'm building a backbone app for the first time - and its going great!

However, I don't think I am creating views for my collection of models in the correct way and when I bind events they fire for every view when I only want them to fire for one.

Here is my backbone code (a snippet):

(function(){ Series = Backbone.Model.extend({ defaults:{ active:false } }); SeriesGridItemView = Backbone.View.extend({ el:'#model-grid', defaults: { active : false }, initialize: function(){ this.render(); this.listenTo(this.model, 'change', this.setState); }, render: function(){ this.template = _.template( $('#template-model-grid-item-view').html() ); this.view = $(this.template(this.model.toJSON())).appendTo(this.$el); }, setState: function(){ this.active = this.model.get('active'); this.view.toggleClass('active',this.active); }, events: { 'click':'toggle' }, toggle: function(e){ e.stopPropagation(); e.preventDefault(); console.log('clicked'); return false; } }); SeriesCollection = Backbone.Collection.extend({ model: Series, setPrice : function(p){ this.forEach(function(m){ var active = 0; _.each(m.get('vehicles'),function(v){ if(v.price <=p){ v.active = true; active++; } else{ v.active = false; } }); m.set('active',active>0); }); } }); series = new SeriesCollection(window.BMW.data.series); series.forEach(function(m,i){ var c = i+1; if(c > 3){ c%=3; } m.set('column','1'); new SeriesGridItemView({model:m}); }); })();

And here is the JSON that constructs the models:

window.BMW.data.series = [ { seriesId:1, name:'1 Series', slug:'1-series', order:0, vehicles:[ { seriesId:1, price:200 }, { seriesId:2, price:300 } ] }, { seriesId:2, name:'3 Series', slug:'3-series', order:1, vehicles:[ { seriesId:1, price:400 }, { seriesId:2, price:500 } ] }, { seriesId:3, name:'4 Series', slug:'4-series', order:3, vehicles:[ { seriesId:1, price:100 }, { seriesId:2, price:300 } ] }, { seriesId:4, name:'6 Series', slug:'6-series', order:4, vehicles:[ { seriesId:1, price:100 }, { seriesId:2, price:300 } ] }, { seriesId:6, name:'X3', slug:'x3', order:5, vehicles:[ { seriesId:1, price:500 }, { seriesId:2, price:800 } ] } ];

And here is my template for the views

<script type="text/template" id="template-model-grid-item-view"> <div id="series-<%=seriesId%>" class="grid-item-view column-<%=column%>"> <div class="label"><%= name %></div> <div class="thumbnail"> <img src="/Content/themes/BMW/img/series/small/<%= slug %>.png"/> </div> </div> </script>

<strong>The problem</strong> - the views assemble correctly but when I click one view the event fires on all of the views! Can someone please point me in the right direction?




Since you omitted the selector in your events object of your views the following applies

Per the Backbone <a href="http://backbonejs.org/#View-delegateEvents" rel="nofollow">Documentation</a>: Omitting the selector causes the event to be bound to the view's root element (this.el).

The problem is each of the SeriesGridItemView's bind click events to #model-grid and each view is a child of #model-grid. In your example, you register 5 click events and when you click on any of your views, all 5 events are triggered.

Without changing any of your other code, one solution is to setup you events object to return a function so you can specify an id selector for each of your views.

events: function() { var selector = '#series-' + this.model.get('seriesId'); // this id corresponds to your template id var ev = {}; ev['click ' + selector] = 'toggle'; return ev; },

Another option and the one I prefer, is to not specify #model-grid as your root element for all your views. It would end up looking like: <a href="http://jsbin.com/upowew/6/edit" rel="nofollow">demo</a>

SeriesGridItemView = Backbone.View.extend({ // remove the following line el:'#model-grid', // .. all else is the same ../ }); series = new SeriesCollection(window.BMW.data.series); series.forEach(function(m,i){ var c = i+1; if(c > 3){ c%=3; } m.set('column','1'); $('#model-grid').append(new SeriesGridItemView({model:m}).el); });

A side suggetion


In your render function, there's no need to create variable, you can access your element by using $:

render: function(){ this.template = _.template( $('#template-model-grid-item-view').html() ); this.$el.append(this.template(this.model.toJSON()))); }, setState: function(){ this.active = this.model.get('active'); this.$el.toggleClass('active',this.active); }, </li> </ol>


  • How to remove button text responsively in JQuery Mobile
  • Backbone: bind event happen multiple times
  • How to organize Backbone collection with a specific selection?
  • How convert a POJO into a readable string on Android for debugging?
  • Stop table row toggle upon clicking link
  • Select more checkbox by value or id
  • Angular/Ionic handling successful 200 as an error
  • How do I refer to an appended item in jQuery?
  • Invoke click events on two superimposed, non-hierarchical elements
  • Add click event on window, but ignore all links that start with https
  • jquery - how to CUT LI elements from one UL to another UL
  • Angular JS: Javascript not working inside custom directive template
  • Clockpicker: How to prevent click on input to open clockpicker
  • How to drag image clone after drop.?
  • Programmatically change first page jQuery Mobile shows
  • load a page using POST to iframe
  • AJAX jquery json sending array to php
  • How I can I delay the expansion of a collapsible until its content is fetched?
  • JITSU FAILED TO INSTALL OSX [node 0.8.17 and NPM 1.2.0] WTF
  • Bootstrap Carousel Next/Prev not working
  • jQuery panel slider opens with button click but won't close
  • JQuery Mobile 1.4 How to Disable Hover Effect on Mobile Devices
  • Onclick or href which is best for opening an link in button
  • Difficult to stop infinite CSS animation in Android browser
  • jQuery toggle hide on click elsewhere
  • Jquery Show & ScrollTop (or ScrollTo)
  • CSS: How to fix overlapping divs
  • Change navbar in bootstrap if user login
  • Android Chronometer starts and stops but carries on counting when stopped
  • Ajax Upload File: $_FILES is empty but files exists in request header
  • Make VS2015 use angular-cli ng at build time in a .NET project
  • How to clear text inside text field when radio button is select
  • Why ng-show works with ng-repeat but ng-if doesn't? [duplicate]
  • Can a Chrome extension content script make an jQuery AJAX request for an html file that is itself a
  • Upload files with Ajax and Jquery
  • jquery mobile loadPage not working
  • How to pass list parameters for each object using Spring MVC?
  • Data Validation Drop Down Box Arrow Disappearing
  • Proper way to use connect-multiparty with express.js?
  • How do you join a server to an Active Directory (domain)?