mbow
mbow

Reputation: 147

backbone js view event binding only to views elements

Hi I'm learning backbone and I am having trouble with binding events to views. My problem is that I have a view constructor that when called, binds all views to a button press event that is only part of one view. I would like the button press event to be bound to only the 1 view that contains the button.

http://jsbin.com/tunazatu/6/edit?js,console,output

  1. click on all of the view buttons
  2. then click back to view 1
  3. click the red button (all view's models console.log their names)

So I've looked at the code from this post mutliple event firing which shows that you can have multiple views that have the same el thru tagName but map events only to their html elements. This is also what is done in the localtodos example from Jérôme Gravel-Niquet

I have also tried not declaring el /tunazatu/7/edit?js,console,output but then it seems like no event gets bound.


    var AppView = Backbone.View.extend({
    tagName:"div",  //tagName defined
    getName:function(){
      console.log(this.model.get('name'));
    },
    initialize:function(options){
      this.listenTo(this.model, 'change', this.render);
      var temp_mapper = {appView1:'#route1',appView2:'#route2',appView3:'#route3'};
      var m_name = this.model.get('name');
      this.template = _.template($(temp_mapper[m_name]).html());  //choose the correct template
    },
    render:function(){
      var temp = this.template(this.model.toJSON()); //populate the template with model data
      var newElement = this.$el.html(temp);  //put it in the view's tagName
      $('#content').html(newElement);
    },
    events:{
      "click button":"log"
    },
    log:function(){
      this.getName();
    }
  });

Upvotes: 1

Views: 3202

Answers (1)

mu is too short
mu is too short

Reputation: 434805

Your problem is that your AppView really looks like this:

var AppView = Backbone.View.extend({
    el: "#content",
    //...

Every time you create a new AppView, you bind another event delegator to #content but you never remove those delegations. If you create three AppViews, you end up with three views listening to click button inside #content.

I would recommend two things:

  1. Avoid trying to re-use views, create and destroy them (via View#remove) as needed. Views should be lightweight enough that putting them together and tearing them down should be cheap.
  2. Don't bind multiple views to the same el. Instead, let each view create its own el and then let the caller put that el inside some container.

If you do both of those things then your problem will go away. Your AppView would look more like this:

var AppView = Backbone.View.extend({
  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this; // Common practise, you'll see why shortly.
  },
  // As you already have things...
});

Then your router methods would look more like this:

view1: function() {
  if(this.appView)
      this.appView.remove();
  this.appView = this.createView('appView1');
  $('#content').html(this.appView.render().el);
  // that `return this` is handy ----------^^
},

If you must stick with your current approach then you'll have to call undelegateEvents on the current AppView before you render another one and delegateEvents on the new AppView after you render it.

But really, don't be afraid to destroy views that you don't need right at this moment: destroy any view that you don't need on the page right now and create new instances when you need them. There are cases where you don't want to destroy your views but you can usually avoid it.

Upvotes: 1

Related Questions