Search code examples
menubackbone.jsmenubar

Highlighting menu/submenu in accordance with the rendered view


I have a fairly large Backbone app with Menu/Submenu being a separate view. Inside the menu view i have the logic to handle click event on li and highlight that. However i am stuck on how to highlight a particular li when i navigate to another view from within the application (using the router, for eg.)

Options available:

  1. From each of the Views render(), access the menu div and highlight the required li
  2. Use Event mechanism and from each of the views render() trigger an event like 'CustomerUpdate::render'.

I feel 2] is the right way to do it. But i am open to suggestions.

What techniques do you follow?


Solution

  • (1) is a bit nasty, that leaks the menu's internal state and structure all over the place. You'll end up with your main views tightly coupled with your menu, that leads to a small ball of mud and small balls of mud always grow into big balls of mud.

    I think (2) is on the right track but I'd pull it apart a little more. The current view is part of your application's state and switching views through a router is a change in your application's state. What do we use in Backbone to track state and state changes? We use models and "change" events. If you have a dedicated global model for your application's state:

    AppState  = Backbone.Model.extend({});
    app_state = new AppState;
    

    Then the view that manages the menu could bind to changes in app_state:

    initialize: function() {
        _.bindAll(this, 'change_current_view');
        app_state.on('change:current_view', this.change_current_view);
    }
    

    and the event handler could deal with the <li>s:

    change_current_view: function() {
        this.$('li').removeClass('current');
        // This selector is, of course, just for illustration
        this.$('#' + app_state.get('current_view')).addClass('current');
    }
    

    Then your router can swap the view and app_state.set({ current_view: '...'}) to trigger the auxiliary actions. You could even have something, such as an application level view, that listens for "change:current_view" and let that listener deal with swapping the view; that would simplify your router. Here's a quick demo to help illustrate what I'm talking about:

    http://jsfiddle.net/ambiguous/fr8sG/

    This "application state model" approach is quite useful in general; you can easily add more bits of state to the app-model, set up preferences editors, etc. You'll also get persistence and application initialization almost for free.