6

I am a very beginner in backbone.js.
My page navigation looks like this:

enter image description here

The left navigation defines four view types, while the top navigation should update the datamodel and re-render the current view (that's what I have in mind).
I want to allow the user to bookmark the current view and category, according to his/her personal preference (and perhaps store the setting in the browser's localstorage).
The two menus can be used interchangeably, meaning that the user can decide to show a different view with the current category's model, and the user can choose a different category within the current view.

I have some trouble figuring out how I should configure my router for this in a stable way.
Note that there may be additional parameters behind this path, such as displaying an active marker on the map based on a profile_id.

Now, I had the idea of doing something like this:

var AppRouter = Backbone.Router.extend({
        routes: {
            ":view/:category": "aggregatefunction" 
        }
    });

But I'm pretty unsure if this will lead me to what I need.
Since I want to use the menus interchangeably and make them bookmarkable, I already get stuck on creating the links.

Can you just give me some advice regarding the structure and notify me of potential pitfalls to help me on the way?
Any supplementary advice is of course welcome as well.
Thanks

Edit
For the bonus, I would like to read a few more opinions.
I still have some trouble building and adapting the hrefs in the menu anchor tags dynamically, while at the same time being able to trigger the events (change category / or change view). I'm looking for the most stable solution to this problem.
Accompanied with some code per illustration if that would be possible.
Thanks.

html_programmer
  • 18,126
  • 18
  • 85
  • 158

3 Answers3

5

Hmm, I think one way to look at this is that the most important part is the View and the Categories are actually less important, they could be considered like a filter. It could even make sense to have a View and no Category (to see 'All'), but here I am just guessing what you app could be doing...

The reason I am saying that is that I assume you are going to have 4 Backbone Views (Map, Livestream, RSS, etc.) but no specific views for those categories. So when switching categories, you don't actually switch view, you just re-render it with a different param, correct?

Then for me, the router should be something like:

'map/:category': '_map'
'rss/:category': '_rss'
...

One route for each main view, and the category as a param to the callback. People can then bookmark an url such as #map/events or #rss/places_to_eat but internally, you are managing 4 clean views.

Later, it'll be easier to use splats to allow for views showing multiple categories at once (splats start with a * in the route definition).

Just my two cents!

Enders
  • 708
  • 1
  • 4
  • 11
  • Okay, thanks for your feedback. That sounds reasonable: you are right that I am using the navigation as a "filter". I am going to give this approach a try this evening and accept tomorrow if all went well. I already gave +1 for the approach. Thanks for the notification of foreseeing multiple categories later on. – html_programmer Dec 03 '13 at 15:01
  • Thanks for your patience, well I still have some trouble implementing the logic. In the href of the horizontal and vertical menus, I should define the URI ie. the absolute path -> view / splat -> category. But I suppose that there is no other way than to trigger the router programmatically and to build the URI dynamically (ie. get the current splat when switching the view, or getting the current view when switching the category)? It is obviously not possible to use the links in the href tag of the menu anchor attributes. Thanks. – html_programmer Dec 07 '13 at 00:03
  • I see what you mean... I was assuming you would update the menu's anchors based on the current situation (for instance, if you clicked on '#map', then all the links in the top menu would become #map/events, #map/fun_stuff, etc), but I see now that this may be impractical for some cases. I agree with your solution: the 'links' in the menu would be more like buttons, generating a new route (based on current route) and navigating programmatically to it, to allow people to bookmark the URL or have internal links to specific combinations of views/filters. – Enders Dec 07 '13 at 01:11
  • 1
    Of course, you don't need to put all the logic to generate the new urls into the menu views, it could still be in the router, which could have a "changeView(newView)" and a "changeFilters(newFilters)" method, this way, you keep all the details of route handling into one place. That's probably obvious but who knows how many coffees you have had today. ;) – Enders Dec 07 '13 at 01:13
  • I'm breaking my balls over this, but definitely worth it. I have to choose for the best solution to determine this, and make it the most future proof possible. The problem is that I see quite a lot of possibilities in this case. Your solution to manage everything in the router sounds very attractive as well. Next to that, I've been thinking about creating a model that declares views and categories and updating the href in the menus with the underscore templating engine when the model changes. Sounds typically backbone, but I'm not sure if this is overkill. – html_programmer Dec 07 '13 at 10:56
  • Hmm, in my experience, everything dealing with url hashes is best left to the Router, and everything dealing with views (especially templates) is best left to View. I often use a pattern of a view for the whole current content ("body" or whatever overall container div you have) and then a subview for each part (in your case a subview for the top menu, a subview for the left menu and a subview for the main content area). – Enders Dec 08 '13 at 13:05
  • Then I might use a intermediary model to coordinate the current state (which view, which categories), but the model itself will have no view logic, it won't know what template to render or whatever. For instance, you can give this appState model to each of the view, and then from the left menu view, do a appState.set("current_view", "rss") and then from the main content view, listen to change:current_view to render based on the appState.get("current_view"). – Enders Dec 08 '13 at 13:07
  • Thanks @Enders. I came to the same conclusion of using a model to keep the state. I will answer below but accept your answer, as the logic is there. Let me know if this was something you had in mind. – html_programmer Dec 09 '13 at 14:18
1

I always found Backbone's router to be horrible for this very reason: it is one dimensional. I wrote a jQuery plugin that provides dependent and independent variables. Check it out at http://plugins.jquery.com/uriAnchor/. Building a bookmarkable app with model and view like you have outlined is quite simple with this, although I wouldn't waste my time with Backbone. Let me know if you want to learn more. In any event, I hope this helps.

Michael Mikowski
  • 1,269
  • 1
  • 10
  • 21
0

Based on the reply + comments of @enders, I ended up creating an intermediary model: Here is a demo (without showing a view yet, but managing the dynamic routing): http://www.zwoop.be/bb/index.php

define([
  'jquery',
  'underscore',
  'backbone',
], function($, _, Backbone, Text, Leftnav){
  var Navstate_Model = Backbone.Model.extend({
      defaults: {
            view: '',
            category: ''
        },
        initialize: function(){
        }
  });
  // Our module now returns our view
  return Navstate_Model;
});

As for the routes:

define([
  'jquery',
  'underscore',
  'backbone',
], function($, _, Backbone){
  var AppRouter = Backbone.Router.extend({
    routes: {
      // Define some URL routes
      '': 'landing_page', 
      ':views/:categories': 'showView',

      // Default
      '*actions': 'defaultAction'
    }, 
    landing_page: function(){
        app.models.navstate_Model.set("view", "map"); 
        app.models.navstate_Model.set("category", "events");         
    }, 
    showView: function(view, category){
        app.models.navstate_Model.set("view", view); 
        app.models.navstate_Model.set("category", category); 
        app.views.leftnav_View.render();
        app.views.topnav_View.render(); 
        console.log(view + ";" + category); 
    }
  });
html_programmer
  • 18,126
  • 18
  • 85
  • 158