Click menu item to highlight in Backbone View
backbone.js, css, html, javascript, jquery
Solution
Create a menu item model
var MenuItem = Backbone.Model.extend({
title: 'Default Title',
isSelected: false
});
and items collection, that would listen to any model selection change event
var MenuItemCollection = Backbone.Collection.extend({
model: MenuItem,
initialize: function() {
this.on('change:isSelected', this.onSelectedChanged, this);
},
onSelectedChanged: function(model) {
this.each(function(model) {
if (model.get('isSelected') === true && !model.hasChanged('isSelected')) {
model.set({isSelected: false});
}
});
}
});
After that create a view each for menu item
var MenuItemView = Backbone.View.extend({
tagName: 'li',
events: {
'click' : 'highlight'
},
initialize: function() {
_.bindAll(this);
this.model.on('change:isSelected', this.onSelectedChanged);
},
render: function() {
this.$el.text(this.model.get('title'));
return this;
},
onSelectedChanged: function() {
if (this.model.get('isSelected') === true) {
this.$el.addClass('active');
}
else {
this.$el.removeClass('active');
}
},
highlight: function() {
this.model.set({isSelected: true});
}
});
and menu itself like
var MenuView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
_.bindAll(this);
},
render: function() {
this.collection.each(function(model) {
var item = new MenuItemView({model: model});
this.$el.append(item.render().el);
}, this);
return this;
}
});
Full working js fiddle with comments at http://jsfiddle.net/Kf3SS/
Problem
This is a simple problem for beginner but so far I haven't seen a solution that fits my need. Basically I got a simple menu with `ul` and `li`. There are 2 requirements: Req1: When click on one, the `li` will get new class `.active`. Req2: Menu items are dynamic, meaning I should be able to add or remove any menu item (by using some other button). There are 2 ways to do this: Method 1: Tranversing for each MenuView as MenuItem I have a MenuView with something like this ``` el: $('li'), events: { "click" : "highlight" }, highlight: function(e) { thisParent = $(e.target).parent(); thisParent.siblings('.active').removeClass('active'); thisParent.addClass('active'); }, ``` Pro: Easy. This is what I have now. Con: Dependency on the html structure. What if it's changed to `div` instead with many layers. Method 2: One View for the MenuCollection Create a MenuItemCollection and use MenuView for that collection instead. The `el` for MenuView will be `ul` (instead of `li`). The HTML will look like this with separate `id`: ``` <ul> <li id="leftmenu-one">one</li> <li id="leftmenu-two">two</li> <li id="leftmenu-three">three</li> </ul> ``` Then when a click event is detected, do 2 things: 2a. Remove all `.active` class in `ul li` 2b. Add `.active` class to the `e.target` DOM Pro: Decoupling html design Con: Little more code. QUESTION: I think most people would say Method 1 is bad. But is there method 3, 4, 5... that are better? How to handle the adding of new menu item?