Node Tutorial Part 6

20 Dec 2010 | By Alex Young | Tags server node tutorials lmawa nodepad

Welcome to part 6 of Let’s Make a Web App, a tutorial series about building a web app with Node. This series will walk you through the major areas you’ll need to face when building your own applications. These tutorials are tagged with lmawa.

Previous tutorials:

Before starting this tutorial remember to start up a mongo daemon if your computer doesn’t run one automatically.

In the last part we looked at authentication and sessions. We used the particularly cool concept of middleware to build some seamless access control. This week I’m going to demonstrate how to make the interface more interesting using jQuery.

Interface Design

When I design interfaces I usually plan out a rough idea before developing the app. This is usually known as top-down design. Once the interface seems workable, I move on to develop the API with a simple interface and tests, just like we’ve been doing so far in this tutorial series.

I like to sketch out interfaces with graph paper, a mechanical pencil, and a good eraser. I keep the sketches rough so my colleagues know they’re not finished designs, they’re ideas that will evolve as we discuss the project.

A simple sketch of Nodepad suggested the following:

  • The interface could use two panels like a desktop app, one for the list of notes and the other for the note body
  • A save button could appear at the bottom, but an auto-save feature would be nice too
  • Single-clicking a note loads it, double-click allows the title to be edited
  • We need account settings for email/password change
  • Editing could work with XMLHttpRequest, because we already have JSON support

Cheating

One of the most important things when building interfaces is to cheat as much as possible. When I’m programming I don’t spend hours working on code that’s already available in a well-written library, and the same can be said for design. I don’t need to draw every icon I need, and I don’t need to reinvent the wheel for layouts either.

Today there are a lot of solutions available, from CSS frameworks to GUI-heavy projects like Cappuccino. For Nodepad we’re going to use jQuery UI which sits in the middle. It gives us a lot of bang for buck when combined with a solid theme.

For the theme, I’ve decided to use Aristo (demo). It’s not necessarily the best theme out there, but I’ve got a lot of experience using it and I think it looks great.

Including Aristo and jQuery UI

I’ve downloaded Aristo from GitHub and put it in public/stylesheets/aristo. Then we just need to load jQuery UI and the new stylesheet in the views/layout.jade template:

link(rel='stylesheet', href='/stylesheets/aristo/jquery-ui-1.8.5.custom.css')
script(type='text/javascript', src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js')

Page Structure

Our interface needs two columns, a header, a document body for editing, and some buttons for document management. In Jade it might look like this:

div(class='outline-view', id='left')
  div(id='DocumentTitles')
    ul(id='document-list')
      - for (var d in documents)
        li
          a(id='document-title-' + documents[d].id, href='/documents/' + documents[d].id)
            =documents[d].title

  ul(class='toolbar')
    li
      a(href='/documents/new')
        +
    li
      a(href='#', id='delete-document')
        -

div(class='content-divider')

div(class='content')
  div(id='editor-container')
    textarea(name='d[data]', id='editor')
      =d.data || ''

ul(id='controls',class='toolbar')
  li
    a(href='#', id='save-button') Save

The first part, outline-view is a div that contains the document list. This is the code we’ve seen before. I’ve positioned these with absolute and I’m using some JavaScript on resize and focus to resize the document list and button toolbars.

The selected document is displayed using some CSS gradients:

.outline-view ul .selected {
  color: #fff;
  background-color: #8897ba;
  background: -webkit-gradient(linear, left top, left bottom, from(#b2bed7), to(#8897ba));
  background: -moz-linear-gradient(top,  #b2bed7,  #8897ba);
}

It doesn’t matter if browsers don’t support CSS3 gradients, it’ll look fine with just the darker colour.

Selecting Documents

Recall that our API requires .json to be appended to the URL to get JSON data back. We just need some simple jQuery event handling to load the document from the server:

$('#document-list li a').live('click', function(e) {
  var li = $(this);

  $.get(this.href + '.json', function(data) {
    $('#document-list .selected').removeClass('selected');
    li.addClass('selected');
    $('#editor').val(data.data);
    $('#editor').focus();
  });

  e.preventDefault();
});

This binds a click handler that will fire whenever a document title is clicked. It fills out the textarea with the data value from the JSON response. Rather than a normal event, live is used to set up a delegate in case the document list changes.

Saving Documents

Something I like to do when creating dynamic interfaces is to set id attributes based on database IDs, using a simple naming convention. In Nodepad I’ve used DOM ids like this: document-844ce17994ba1b87d359000001. To retrieve the database ID we just need to get the last part, which is easy if we split on the hyphens.

Once that convention is established, we can use a mini jQuery plugin to extract item IDs:

$.fn.itemID = function() {
  try {
    var items = $(this).attr('id').split('-');
    return items[items.length - 1];
  } catch (exception) {
    return null;
  }
};

This makes saving documents when the save button is pressed straightforward enough:

$('#save-button').click(function() {
  var id = $('#document-list .selected').itemID(),
      params = { d: { data: $('#editor').val(), id: id } };
  $.put('/documents/' + id + '.json', params, function(data) {
    // Saved, will return JSON
  });

There isn’t actually a HTTP verb for put in jQuery, so I defined one:

$.put = function(url, data, success) {
  data._method = 'PUT';
  $.post(url, data, success, 'json');
};

Progress

We haven’t actually used any jQuery UI so far, but we’ll get to that in the next part. So far we’ve got a simple little editor that’s starting to look like something more friendly and usable.

I haven’t had time to browser test yet, so stick to WebKit or Firefox.

The latest Nodepad commit was dd40b.

Update: I’ve changed the Nodepad README to include more details on library, binary and operating systems that I’ve tested it against. This may help people who’ve been having trouble running it.


blog comments powered by Disqus