Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to get selected model in option view in Backbone

Consider the below code. If I create a change event handler in Select View, What would be the cleanest and best way to get the selected model of the option view without assigning data-cid attribute in the option view. Im trying to keep the truth out of the dom and do this Backbone way:

var ItemView = Backbone.View.extend({
tagName: 'option',
initialize:function(){        
    this.template= _.template($('#menu_item_view').html());    
},    
render:function(){        
    this.$el.html(this.template(this.model.toJSON()));        
    return this;        
}
});

var CollectionView = Backbone.View.extend({
  tagName: 'select',
  initialize:function(){        
    this.collection = new ItemCollection();            
    this.collection.on('sync',this.render,this);            
    this.collection.fetch();
 },    
 render:function(){        
    this.$el.html(this.collection.map(function( item ){            
        return new ItemView ({model:item}).render().el;        
    },this);      
    return this;        
 }
});
like image 281
Alex Shilman Avatar asked Aug 09 '14 05:08

Alex Shilman


1 Answers

You are right, you should NOT use anything in the DOM.

The idea to solve this is easy, at ItemView listen for the click event, then in the listener just do something like it:

this.model.trigger('selected', this.model);

This trigger an event in the model and pass as argument the model as itself(to know wish has been selected). Events triggered in models are propagated to its collection.

Then in CollectionView listen for:

this.collection.on('selected', this.selectedHandler, this); 

SelectedHandler is going to receive the selected model as argument, as you passed it in the trigger.

Update: adding sample code. Basically as the DOM element option did not trigger as itself a DOM event, we add a "plugin" in the select DOM element to do it.

var ItemView = Backbone.View.extend({
  tagName: 'option',
  events : {
    'option_changed' : 'optionChangedHandler'
  },
  initialize:function(){        
    this.template= _.template($('#menu_item_view').html());    
  },    
  render:function(){        
    this.$el.html(this.template(this.model.toJSON()));        
    return this;        
  },
  optionChangedHandler : function(){
    this.model.trigger('selected', this.model);
  }
});

var CollectionView = Backbone.View.extend({
  tagName: 'select',
  events : {
    'change' : 'changeHandler'
  },
  initialize:function(){        
    this.collection = new ItemCollection();            
    this.collection.on('sync',this.render,this);    
    this.collection.on('selected',this.selectedModel, this);            
    this.collection.fetch();
 },    
 render:function(){        
    this.$el.html(this.collection.map(function( item ){            
        return new ItemView ({model:item}).render().el;        
    },this);      
    return this;        
 },
 selectedModel : function(model){
    console.log('it is magic: ', model);
 },
 changeHandler : function(){
   this.$("option:selected").trigger('option_changed'); 
 }
});
like image 140
Daniel Aranda Avatar answered Oct 20 '22 16:10

Daniel Aranda