LDK
LDK

Reputation: 2575

Structuring my backbone.js application

I'm in the process of creating a Backbone.js app using Require.js. Each view file corresponds to one resource (e.g. 'News'). Within each view file, I declare a backbone view for each action ('index', 'new', etc). At the bottom of the view file I receive the necessary info from the router and then decide which view to instantiate (based on the info passed in from the router).

This all works well, but it requires lots of code and doesn't seem to be the 'backbone.js way'. For one thing, I'm rellying on the url to manage state. For another, I'm not using _.bind which pops up in a lot of backbone.js examples. In other words, I don't think I'm doing it right, and my code base smells... Any thoughts on how to structure my app better?

router.js

define([
  'jquery',
  'underscore',
  'backbone',
  'views/news'], 
  function($, _, Backbone,  newsView){
    var AppRouter = Backbone.Router.extend({
        routes:{
            'news':'news',
            'news/:action':'news',
            'news/:action/:id':'news'
        },

        news: function(action, id){
            newsView(this, action, id).render();
        }
    });


    var intialize = function(){
        new AppRouter;
        Backbone.history.start()
    };

    return{
        initialize: initialize;
    };
}

news.js ('views/news')

define([
  'jquery',
  'underscore',
  'backbone',
  'collections/news',
  'text!templates/news/index.html',
  'text!templates/news/form.html'

  ], function($, _, Backbone, newsCollection, newsIndexTemplate, newsFormTemplate){

    var indexNewsView = Backbone.View.extend({
        el: $("#content"),

        initialize: function(router){
            ...
        },

        render: function(){
            ...
        }
    });

    var newNewsView = Backbone.View.extend({
        el: $("#modal"),

        render: function(){
            ...
        }
    });

    ...

    /*
     *  SUB ROUTER ACTIONS
     */

    var defaultAction = function(router){
      return new newsIndexView(router);
    }

    var subRouter = {
      undefined: function(router){return defaultAction(router);},

      'index': function(router){ return defaultAction(router);},

      'new': function(){
        return new newNewsView()
      },

      'create': function(router){
        unsavedModel = {
          title : $(".modal-body form input[name=title]").val(),
          body  : $(".modal-body form textarea").val()
        };
        return new createNewsView(router, unsavedModel);
      },

      'edit': function(router, id){
        return new editNewsView(router, id);
      },

      'update': function(router, id){
        unsavedModel = {
          title : $(".modal-body form input[name=title]").val(),
          body  : $(".modal-body form textarea").val()
        };

        return new updateNewsView(router, id, unsavedModel);
      },
    }

    return function(router, action, id){
      var re = /^(index)$|^(edit)$|^(update)$|^(new)$|^(create)$/
      if(action != undefined && !re.test(action)){
        router.navigate('/news',true);
      }
      return subRouter[action](router, id);
    }


  });

Upvotes: 3

Views: 3303

Answers (3)

timDunham
timDunham

Reputation: 3318

I'm using require.js and backbone as well I think the main difference that i'd suggest is that each file should return just one view, model, router or collection.

so my main html page requires my main router. That router is a module that requires a few views based on each of it's routes, and a bootstrapped model. Each router method passes the relevant bootstrapped model piece to the relevant view.

From there it stays really clean as long as each file is just 1 backbone thing (model, collection, view, router) and requires just the elements it uses. This makes for a lot of js files (I have about 100 for my current project) but that's where require.js optimization comes into play.

I hope that helps.

Upvotes: 2

nrabinowitz
nrabinowitz

Reputation: 55678

While I feel like it's important to emphasize that there isn't really a "Backbone.js way", it does seem like you're replicating work Backbone should be doing for you.

I agree that it makes sense to have a specialized Router for each independent section of your application. But it looks at first glance like what you're doing in your "sub-router" section is just recreating the Backbone.Router functionality. Your AppRouter doesn't need to deal with /news URLs at all; you can just initialize a NewsRouter with news-specific routes, and it will deal with news-related URLs:

var NewsRouter = Backbone.Router.extend({
    routes:{
        'news':             'index',
        'news/create':      'create',
        'news/update/:id':  'update',
        'news/edit/:id':    'edit'
    },

    index: function() { ... },

    create: function() { ... },

    // etc
});

As long as this is initialized before you call Backbone.history.start(), it will capture URL requests for its routes, and you never have to deal with the AppRouter. You also don't need to deal with the ugly bit of code at the bottom of your view - that's basically just doing what the core Backbone.Router does for you.

Upvotes: 6

Chris Biscardi
Chris Biscardi

Reputation: 3153

Why don't you structure your routes like this:

        routes:{
            'news':'news',
            'news/edit/:id':'editNews',
            'news/new':'newNews',
            ...
        }

Upvotes: 0

Related Questions