Using Bootstrap alerts with Express.js 4

It’s often handy to be able to display a notification to users, noting a successful operation for example, or showing errors.

With Express this is normally done using a “flash message”. You’ll need the connect-flash middleware, as it was unbundled in Express 3.

var express = require('express'),
    flash = require('connect-flash'),
    app = express();

app.use(flash());
app.use(function(req, res, next){
    res.locals.success = req.flash('success');
    res.locals.errors = req.flash('error');
    next();
});

The 2nd piece of middleware ensures that flash messages will be available to the template as locals.

router.get('/account/name', function (req, res) {
        var data = {
            firstName: req.user.firstName,
            lastName: req.user.lastName
        };
        res.render('settings_name', data);
    });

    router.post('/account/name', function (req, res) {
        req.user.updateName(req.user.id, req.body.firstName, req.body.lastName, function(err) {
            if (err) {
                req.flash('error', 'Could not update your name, please contact our support team');
            } else {
                req.flash('success', 'Your name was updated');
            }
            res.redirect('/account/name');
        });
    });

The final step is to display the messages when necessary. Bootstrap alerts provide an easy way to do this:

doctype html
html
  head
    link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css")
  body
    if error && error.length > 0
      .alert.alert-danger.alert-dismissible.fade-in(role="alert")
        button.close(type="button" data-dismiss="alert" aria-label="Close")
          span(aria-hidden="true") ×
        p= error
    if success && success.length > 0
      .alert.alert-success.alert-dismissible.fade-in(role="alert")
        button.close(type="button" data-dismiss="alert" aria-label="Close")
          span(aria-hidden="true") ×
        p= success

    script(src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js")
    script(src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js")

Upgrading from Bootstrap 1.4.0 to 2.0

Twitter Bootstrap 2.0 was recently released. They’ve provided an upgrade guide, but it doesn’t list every detail you may have to change. Here’s a list of the things I had to update to get a similar look:

CSS

I added a reference to bootstrap-responsive.css. I’m not sure this really mattered for me, but you never know!

Nav bar

The navbar markup had changed a bit, from:

 <div id="navbar" class="topbar">
  <div class="fill">
	<div class="container">
	  <a class="brand" href="#">App name</a>
	  <ul class="nav">
          ...
          </ul>
	</div>
  </div>
</div>

to:

<div id="navbar" class="navbar navbar-fixed-top">
  <div class="navbar-inner">
	<div class="container">
	  <a class="brand" href="">App name</a>
	  <div class="nav-collapse">
		<ul class="nav">
                ...
		</ul>
	  </div><!--/.nav-collapse -->
	</div>
  </div>
</div>

Grid

The grid layout has changed, from 16 columns to 12.

Tables

.condensed-table is no more, you need .table & .table-condensed

Buttons

The button styles are now prepended with btn e.g. for a dangerous button:

<button class="btn btn-danger">Watch Out!</button>

Alerts

The script has been renamed to bootstrap-alert.js (from bootstrap-alerts.js). The css has changed a bit as well, from:

<div id="alert" class="alert-message error"></div>

to:

<div id="alert" class="alert alert-error"></div>

And the close button has changed from:

<a class="close" href="#">x</a>

to:

<a class="close" data-dismiss="alert">x</a>

(thanks to this article for the tip!).

And finally…

Forms

The default form styling has changed to a “stacked” look, and the required markup has changed as well. To get back to the old look, I had to go from this:

<form>
  <div class="clearfix">
    <label>This:</label>
    <div class="input">
      <input readonly="readonly" value="<%= model.this %>" />
    </div>
  </div>
  ...
  <div class="clearfix">
    <label>That:</label>
    <div class="input">
      <input readonly="readonly" value="<%= model.that %>" />
    </div>
  </div>
</form>

to:

<form class="form-horizontal">
  <fieldset class="control-group">
    <label class="control-label" for="this">This:</label>
    <div class="controls">
      <input readonly="readonly" value="<%= model.this %>" name="this" />
    </div>
  </fieldset>
  ...
  <fieldset class="control-group">
    <label class="control-label" for="that">That:</label>
    <div class="controls">
      <input readonly="readonly" value="<%= model.that %>" name="that" />
    </div>
  </fieldset>
</form>

I’m sure there are other changes, but that was enough for the subset I’m using.

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);