Using Bootstrap with Backbone (Part 2)

In Part 1 we looked at using Backbone alerts. This time, the navbar!

It would be very simple (and not very useful), to create a Backbone View that renders a static navbar.

But we want a modular, composable app; where each section of the application can add it’s own menu items.

We can start with a template:

<div class="fill">
  <div class="container">
    <a class="brand" href="#">MyApp</a>
    <ul class="nav">
      <% _.each(links, function(link) { %>
        <li><a href="<%= link.url %>"><%= link.name %></a></li>
      <% }); %>
    </ul>
  </div>
</div>

Obviously our model will consist of a collection of links:

(function($) {
  var Link = Backbone.Model.extend();

  var LinksCollection = Backbone.Collection.extend({
    model: Link
  });
  
  var NavBarView = Backbone.View.extend({
    el: $('#navbar'),
    render: function(eventName) {
      var self = this;
      $.get("templates/navbar/navbar.htm", function(data) {
        $(self.el).html(_.template(data)({ links: self.model.toJSON() }));
      });
      return this;
    },
    addLink: function(link) {
      this.model.add(link);
    }
  });

  app.navbar = new NavBarView({ model: new LinksCollection() });
  
})(jQuery);

Populated by other modules:

(function() {
  ...
  app.navbar.addLink({ url: "#something", name: "Something" });
})();

Using Bootstrap alerts with Backbone

Developing single page web apps with Backbone.js is an interesting experience. Each individual part of the UI is considered to be a View.

So, for example, if you wanted to display one of Twitter Bootstrap’s alerts you might create a template:

<div id="alert" class="alert-message error fade in">
  <a class="close" href="#">x</a>
  <p><strong><%= title %></strong> <%= message %></p>
</div>

And a module to display it:

MyApp.Errors = {};
 
(function(ns, $) {
  var Error = Backbone.Model.extend();
 
  var errorAlertTemplate = $.get("templates/errors/error-alert.htm", function(data) {
    errorAlertTemplate = _.template(data);
  });

  var renderTemplate = function(self, url, render) {
    if (!self.template) {
      $.get(url, function(data) {
        self.template = _.template(data);
        render();
      });
    } else {
      render();
    }
  };
 
  var ErrorAlertView = Backbone.View.extend({
    el: $('#alert'),
    render: function(eventName) {
      var self = this;
      renderTemplate(self, "templates/errors/error-alert.htm", function() {
        $(self.el).html(self.template(self.model.toJSON()));
      });
      return this;
    }
  });
 
  ns.errorAlert = function(title, message) {
    var error = new Error({ title: title, message: message });
    app.error = new ErrorAlertView({ model: error });
    app.error.render();
    $(".alert-message").alert();
  };
})(MyApp.Errors, jQuery);

You can then use this in your routes:

MyApp.MyModule = {};
 
(function(ns, $, errors) {
  ns.someRoute = function() {
    var somethings = new SomethingCollection();
    somethings.fetch({
      success: function() {
        var view = new SomethingListView({model: somethings});
        view.render();
      },
      error: function() {
        errors.errorAlert("ERROR:", "Failed to retrieve somethings");
      }
    });
  };
})(MyApp.MyModule, jQuery, MyApp.Errors);