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?

Original source