1

EDIT: this question is very similar to this one but it's more "conceptual" one.

Assume a single-page app with a bounce of static links that reflects routes:

<!-- Top navlist -->
<ul class="nav nav-list">
    <li><a class="active" href="#/customers">Customers</a></li>
</ul>

<!-- Left navlist -->
<ul class="nav nav-list">
    <li><a class="active" href="#/customers">Show customers</a></li>
    <li><a href="#/customers/new">Create customer</a></li>
</ul>

I need to set class="active" for one (or more) links based on the current route. Which is the correct approach?

  1. Create Link and LinkCollection models, as long as LinkCollectionView and LinkView, from scratch: this seems overkill to me. And seems useless since links not depend upon server side (they are not dynamically created).
  2. Create Link and LinkCollection models iterating over existing links.
  3. Forget about models and view and manually set class="active" for each route. Something like $('body').find('a[href="#/customers"]').addClass('active'). Seems a duplication of code to me.
  4. Create a "global" AppView view and do something like pt. 3 in render() funcion.

Routes definition example:

<script>
    (function($){
        var MyApp = { Models : {}, Collections : {}, Views : {} };

        // The Router
        MyApp.Router = Backbone.Router.extend({
            routes : {
                '/customers'     : 'showCustomersView',
                '/customers/new' : 'showCreateCustomerView'
            },
            showCustomersView      : function() {
               // Make customers links active
            },
            showCreateCustomerView : function() {
               // Make new customer links active
            },
        });

    })(jQuery);
</script>
Community
  • 1
  • 1
gremo
  • 47,186
  • 75
  • 257
  • 421

1 Answers1

2

I can't speak to the "best practice", but I am fairly certain that involving models solely for the purpose of representing intra-app links is, as you said, definitely overkill and not their intended use.

I personally would do something like pattern #4. In a project I am currently working on, I have an AppView that looks a little something like this:

AppView = Backbone.View.extend({

  events: {
    "click a.internal" : "handleLink"
  },

  handleLink: function (event) {
    var route = $(event.target).attr('data-route');
    router.navigate(route, true);
    return false;
  },

});

I do not use the actual href property on my anchor tags to specify the target route, as I am using pushState. Instead, I use an element class, internal, to indicate an anchor tag which is to be used for my app's internal navigation. I then use another arbitrary element attribute, route, to indicate where the link ought to be going.

A link might look like something like this, then:

<a href="#" class="internal" data-route="projects/3">My Third Project</a>

Adding in the extra bit to add that CSS class you want would then just be a matter of making a jQuery/Zepto call in handleLink.

Again, I don't necessarily believe this is a common/best practice, but at least for my purposes it seems to be sufficiently simplistic and straightforward (and also works with pushState).

Edit: Use steveax's suggestion of data-route for syntax validity sake.

Avi Romanoff
  • 156
  • 6
  • +1 for the explanation. But i think that `router.navigate` is going to break the philosophy behind MVC pattern. It's the router that should retrieve data and serve the correct view. That's all it should do, IMHO. – gremo Mar 05 '12 at 22:09
  • Probably be better to use data-route, valid syntax that way. – steveax Mar 06 '12 at 00:35
  • Good call, steveax. I updated my answer. Gremo, I'm not sure what you mean. The router *is* retrieving the data and serving the view -- all this is doing is letting the router react to link clicks. The query/view logic is still in the router, nothing more, nothing less. – Avi Romanoff Mar 06 '12 at 01:42