1
// Filename: router.js

define(['jquery','underscore','backbone',
'collections/series','views/series/list','text!templates/series/list.html',
'models/series',
    'views/series/details','text!templates/series/details.html',
    'views/series/preview','text!templates/series/preview.html'
], function($, _, Backbone,
        SeriesCollection, SeriesListView, SeriesListTemplate,
        SeriesModel,
        SeriesDetailsView, SeriesDetailsTemplate,
        SeriesPreviewView, SeriesPreviewTemplate
){

_.templateSettings = { interpolate : /\{\{(.+?)\}\}/g };

...

UPDATE:

The reason for all of this is that in my router's function i'm doing this:

 seriesList: function(){
  // We have no matching route, lets display the home page

    var seriesCollection = new SeriesCollection();
    seriesCollection.fetch({success:function(){

        var seriesListView = new SeriesListView({collection:seriesCollection, el:'#page'});
        seriesListView.template = _.template(SeriesListTemplate);
        seriesListView.render();
    }});

}

meaning - i'm connection the template and view when the data returns. it works - but is it good practice?

Guy
  • 12,488
  • 16
  • 79
  • 119
  • i fear it will just grow and grow... – Guy Jun 04 '12 at 01:00
  • after reading about the different approaches in: http://addyosmani.github.com/backbone-fundamentals/#namespacing . i decided to try and fetch them on demand as suggested in: http://addyosmani.github.com/backbone-fundamentals/#organizingmodules – Guy Jun 04 '12 at 01:34
  • You are still loading up the template in your router for no reason. Load the template up inside of the view that needs it, not the Router. You should require.js only the things that you need in the Router and then load the things that those things need inside of their modules. – Mosselman Jun 04 '12 at 14:58

5 Answers5

1

In my opinion right now your router is a kind of God Object. It knows too much. I think it makes sense to refactor the app in order to achieve a more clear separation of concerns. And then your router will not look like above and will not have so many dependencies. For example, you could let views be responsible for its own templates (by the way, and for rendering itself):

// router.js
seriesList: function(){
    var seriesCollection = new SeriesCollection();
    var seriesListView = new SeriesListView({collection:seriesCollection, el:'#page'});
    seriesCollection.fetch();
}

// view/series/list.js
define(['jquery',
       'underscore',
       'backbone',
       'text!templates/series/list.html'], function($, _, Backbone, SeriesListTemplate){

    var SeriesListView = Backbone.View.extend({
        template: _.template(SeriesListTemplate),

        initialize: function (options) {
            this.collection.on('reset', this.render, this);
        }
        ...
    });
    return SeriesListView;
}

Then the according template dependencies will go away from router.js.

theotheo
  • 2,664
  • 1
  • 23
  • 21
  • i agree with your statement about a god object. your suggestion, however, will only take 3 dependencies out. the router.js will still grow as the application grows and will become unreadable.. – Guy Jun 04 '12 at 12:23
1

Have you considered dividing your single route into separate routes?

As the Backbone docs say, be sure to run Backbone.history.start on DOM-ready (for IE) and after you've initiated all routers.

$(function(){
  new WorkspaceRouter;
  new HelpPaneRouter;
  Backbone.history.start({pushState: true});
});

Something I didn't realize is that Backbone.history is the "master" router so you can set .bind events on your child routers to effect just those routes or .bind on Backbone.history to effect them all. Obviously this means you can set helper methods on the master to be reused on all child routers.

Mauvis Ledford
  • 40,827
  • 17
  • 81
  • 86
0

The problem is, at least if I understand it, you are trying to load up everything all at once so that it is available to you for some settings?

For example, why are you loading in the series details template outside of it's view?

Try this answer I gave someone today, I included an example of how AMD would work here: Backbone Design or the gist: https://gist.github.com/2863979

As you can see I don't load up everything in one huge router.js file.

A great resource: http://addyosmani.github.com/backbone-fundamentals/#modularjs

p.s. I haven't come across the concept of a router.js file for backbone and require.js. Where did you get this idea?

Community
  • 1
  • 1
Mosselman
  • 1,718
  • 15
  • 27
  • tnx. your approach seems solid. i came with it after combining the resource you recommended with another i found somewhere today. i added the reason for my approach in the update above. do you think it is valid? – Guy Jun 04 '12 at 02:00
  • What I would/ what I do, is have have the Router of Backbone just trigger events that I handle in my AppView. This way I can do `Event.subscribe('route:home', this.showHome);` or something similar. In an attempt to unload the pressure of either 'define' method receiving so many variables, you should nest your views in a certain way. I am sure you can group some of the smaller views inside of a 'managing' bigger view. Lets say you have many sidebar widgets, load those into a sidebar view. You can probably generalize some of their functionalities this way as well. – Mosselman Jun 04 '12 at 14:57
0

You can move the dependencies to the route handlers:

define(['backbone'], function (Backbone) {

    var Router = Backbone.Router.extend({

        routes: {
            "Series(/)": "seriesList"
        },

        seriesList: function() {
            require(['collections/series', 'views/series/list'], function(SeriesCollection, SeriesListView) {
                var seriesCollection = new SeriesCollection();
                var seriesListView = new SeriesListView({collection:seriesCollection, el:'#page'});
                seriesCollection.fetch();
            });
        } 
    });
});

This makes the define() call more manageable and defers loading until the route is actually used.

Greg McCoy
  • 511
  • 7
  • 7
0

Here's yet another way:

  1. instantiate a router (global or member of the app) which doesn't know about any route
  2. in each view's initialize() method, define routes handled by that view

router.route('tasks', 'tasks', function () { ... })

  1. instantiate all top-level views in main App view, before calling Backbone.history.start()
  2. (optional) navigate to default view route when starting the app

More explanations and sample code at http://mariusa.github.io/writings/handling-backbone-routes.html

Marius
  • 1,659
  • 3
  • 22
  • 31