Flight, ComponentJS

01 Feb 2013 | By Alex Young | Comments | Tags components twitter

Flight

Flight by Twitter

What’s the most sensible thing to do when there’s an established project called Component that aims to make client-side development more modular through reusable components? Invent something else that yet again overloads this increasingly overused term! If you weren’t already confused about components, then get ready to unlearn everything you’ve learned.

I was expecting this, however. After seeing Bower, I felt like it really needed another project to further abstract client-side development, and that appears to have been satisfied by the release of Flight.

Flight (GitHub: twitter / flight, License: MIT, bower: flight) from Twitter is a new framework that maps “behaviour” to DOM nodes. To do this it brings together a few things you’re probably already familiar with: multiple inheritance (mixins), the AMD pattern, and the observer pattern. The supplied Flight Mail example app is built using RequireJS, so you can see why AMD is relevant here.

Flight apps look a bit like Backbone/RequireJS apps. They both use AMD and rely on events for communication. However, Flight is deceptively different. Which isn’t necessarily a bad thing, because we’ve argued about MVC/MVVC/MV* for a long time at this point.

The authors define a component in Flight as a constructor with properties mixed in. Each component has event handling, and is eventually attached to a DOM node. They can’t refer to each other directly – communication is purely through events.

That last point is potentially important, because it demonstrates the authors have a good sense of one of the major issues with client-side development: writing reusable, decoupled code. Given that Angus Croll and Dan Webb are contributors to this project, it’s not surprising that there’s a focus on composition.

Although Flight already has a bazillion stars on GitHub (Twitter™!), it’s going to face the same hurdles in adoption as Backbone did: the learning curve. Casual JavaScript developers are going to see AMD, mixin, and “advice”, and struggle to understand how to relate these concepts to their existing development practices.

However, the project has some great ideas and has serious pedigree behind it. It’s different enough to Backbone, AngularJS, and Knockout, so I’ve welcomed it to my rapidly growing client-side development toy box.

ComponentJS

ComponentJS (GitHub: rse / componentjs, License: MPL) by Ralf S. Engelschall is a totally unrelated project that just happens to involve the term “component”. This library is aimed at creating dialog-based hierarchical interfaces for single page apps. It has an OO library, a graphical debugger, UI toolkit, state transitions, and communication using events.

According to the author, this project has been developed since 2009 (although the domain name was created a year ago), so the naming clash is purely coincidental from what I can tell. It has extremely detailed API documentation, and a demo with browsable source code.

Backbone.js Tutorial: Oh No, Not More Tasks

31 Jan 2013 | By Alex Young | Comments | Tags backbone.js mvc node backgoog

Preparation

Before starting this tutorial, you’ll need the following:

  • alexyoung / dailyjs-backbone-tutorial at commit 0491ad
  • The API key from part 2
  • The “Client ID” key from part 2
  • Update app/js/config.js with your keys (if you’ve checked out my source)

To check out the source, run the following commands (or use a suitable Git GUI tool):

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 0491ad

Tasks Continued

A preview of today's tutorial.

The application is now displaying lists of tasks, but you can’t yet interact with them. This tutorial will cover:

  • Adding tasks
  • Editing tasks
  • Deleting tasks
  • Toggling tasks

Most of this content builds on what we did with lists, but it’ll be good practice if you’re looking for more experience with Backbone.

Adding Tasks

Open app/js/views/tasks/index.js and ensure there’s an event binding for addTask:

events: {
  'submit .add-task': 'addTask'
},

In the initialize method, add a listener to this class’s collection:

initialize: function() {
  this.children = [];
  this.collection.on('add', this.renderTask, this);
},

This will make it automatically render new tasks when they’re added to the collection.

The addTask method should call Task.prototype.save to persist the task using Google’s API, after instantiating it with a reference to the current list. It should also render the task once it’s been saved. I’ve passed in { at: 0} because Google Tasks places new tasks at the top of a list. Notice that I prefer to only add tasks once they’ve been successfully saved – that makes this application always require an Internet connection. It may be preferable to save to a local database and sync with Google later, but we’re not going to do that here.

addTask: function() {
  var $input = this.$el.find('input[name="title"]')
    , task = new this.collection.model({ tasklist: this.model.get('id') })
    , self = this
    ;

  task.save({ title: $input.val() }, {
    success: function() {
      self.collection.add(task, { at: 0 });
    }
  });
  $input.val('');

  return false;
},

renderTask: function(task, list, options) {
  var item = new TaskView({ model: task, parentView: this })
    , $el = this.$el.find('#task-list');
  if (options && options.at === 0) {
    $el.prepend(item.render().el);
  } else {
    $el.append(item.render().el);
  }
  this.children.push(item);
},

The renderTask method will receive the options argument, and it uses it to determine how to add the task to the list. The reason I don’t just prepend new tasks is the render method can now be refactored to use this method:

render: function() {
  this.$el.html(this.template());

  var $el = this.$el.find('#task-list')
    , self = this;

  this.collection.fetch({ data: { tasklist: this.model.get('id') }, success: function() {
    self.collection.each(function(task) {
      task.set('tasklist', self.model.get('id'));
      self.renderTask(task);
    });
  }});
}

Open app/js/views/lists/menuitem.js and make it pass in a Tasks collection in the open method where it instantiates bTask.views.tasksIndexView:

bTask.views.tasksIndexView = new TasksIndexView({ collection: new Tasks({ tasklist: this.model.get('id') }), model: this.model });

You’ll need to change the define statement at the top of the file to include the Tasks collection:

define(['text!templates/lists/menuitem.html', 'views/tasks/index', 'collections/tasks'], function(template, TasksIndexView, Tasks) {

Due to how Google’s API works, you’ll need to make a small change to app/js/gapi.js to insert a tasklist ID into the requestContent payload:

Backbone.sync = function(method, model, options) {
  var requestContent = {};
  options || (options = {});

  switch (model.url) {
    case 'tasks':
      requestContent.task = model.get('id');
      requestContent.tasklist = model.get('tasklist');
    break;

Adding tasks should now work – there’s no need for a new template because it’s already been added as part of last week’s tutorial.

Editing Tasks

To edit tasks, a few things are needed:

  • A suitable form template
  • A Backbone.View
  • Event handling for saving the task

Here’s the template, which should be saved to app/js/templates/tasks/edit.html:

<fieldset>
  <legend>
    Task Properties
    <a href="#" data-task-id="" class="pull-right delete-task btn"><i class="icon-trash"></i></a>
  </legend>
  <div class="control-group">
    <label for="task_title">Title</label>
    <input type="text" class="input-block-level" name="title" id="task_title" value="" placeholder="The task's title">
  </div>
  <div class="control-group">
    <label class="radio"><input type="radio" name="status" value="needsAction" > Needs action</label>
    <label class="radio"><input type="radio" name="status" value="completed" > Complete</label>
  </div>
  </div>
  <div class="control-group">
    <label for="task_notes">Notes</label>
    <textarea class="input-block-level" name="notes" id="task_notes" placeholder="Notes about this task"></textarea>
  </div>
</fieldset>
<div class="form-actions">
  <button type="submit" class="btn btn-primary">Save Changes</button>
  <button class="cancel btn">Close</button>
</div>

I’ve included all of the usual Bootstrap classes and markup in this form fragment so it will look nice when it’s rendered.

The corresponding view (app/js/views/tasks/edit.js) should look like this:

define(['text!templates/tasks/edit.html'], function(template) {
  var TaskEditView = Backbone.View.extend({
    tagName: 'form',
    className: 'well edit-task',
    template: _.template(template),

    events: {
      'submit': 'submit'
    , 'click .cancel': 'cancel'
    },

    initialize: function() {
      this.model.on('change', this.render, this);
    },

    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      return this;
    },

    submit: function() {
      var title = this.$el.find('input[name="title"]').val()
        , notes = this.$el.find('textarea[name="notes"]').val()
        , status = this.$el.find('input[name="status"]:checked').val()
        ;

      this.model.set('title', title);
      this.model.set('notes', notes);

      if (status !== this.model.get('status')) {
        this.model.set('status', status);
        if (status === 'needsAction') {
          this.model.set('completed', null);
        }
      }

      this.model.save();
      return false;
    },

    cancel: function() {
      this.remove();
      return false;
    }
  });

  return TaskEditView;
});

This sets up a submit event for catching the form submission, and also an event for closing the form, which is what the cancel method is for.

Now add a method to app/js/views/tasks/index.js that invokes TaskEditView:

editTask: function(task) {
  if (this.taskEditView) {
    this.taskEditView.remove();
  }
  this.taskEditView = new TaskEditView({ model: task });
  this.$el.find('#selected-task').append(this.taskEditView.render().el);
}

And make sure it loads TaskEditView:

define(['text!templates/tasks/index.html', 'views/tasks/task', 'views/tasks/edit', 'collections/tasks'], function(template, TaskView, TaskEditView, Tasks) {

This needs to be called by an individual task, so open app/js/views/tasks/task.js and add this to the open method:

this.parentView.editTask(this.model);

These two views have a lot of coupling between them, which makes TaskView difficult to reuse. However, is it likely that it’ll make sense to use it without TasksIndexView? That’s the kind of question you’ll ask yourself a lot when trying to write maintainable Backbone code.

Deleting Tasks

Add a destroy method to app/js/views/tasks/edit.js:

destroy: function() {
  this.model.destroy();
  return false;
}

Then bind the method to the event on the trash can icon (.delete-task) and also bind an event to the model being deleted:

events: {
  'submit': 'submit'
, 'click .cancel': 'cancel'
, 'click .delete-task': 'destroy'
},

initialize: function() {
  this.model.on('change', this.render, this);
  this.model.on('destroy', this.remove, this);
},

Toggling Tasks

Here’s the icing on the cake, toggling the task status! With this change, the app will really start to feel like a real to-do list app. Open app/js/views/tasks/task.js and add an event binding for the checkboxes in the list – a change event is required for this:

events: {
  'click': 'open'
, 'change .check-task': 'toggle'
},

Then the toggle method just needs to toggle the status attribute based on the checkbox’s state:

toggle: function() {
  var id = this.model.get('id')
    , $el = this.$el.find('.check-task')
    ;

  this.model.set('status', $el.attr('checked') ? 'completed' : 'needsAction');
  if (this.model.get('status') === 'needsAction') {
    this.model.set('completed', null);
  }

  this.model.save();
  return false;
}

Google’s nomenclature for the task state is completed and needsAction, which takes a bit of digging in the documentation to find out.

Summary

It’s taken a while to get this far, but working with unfamiliar APIs with their idiosyncrasies can take a lot of patience. And if you try running the code from this project, make sure you actually have some tasks and lists in Gmail already – it doesn’t work tell well without any. I’ll fix it later!

The full source for this tutorial can be found in alexyoung / dailyjs-backbone-tutorial, commit 9691fc1.

Node Roundup: 0.9.8, Queen, AssetViz

30 Jan 2013 | By Alex Young | Comments | Tags node modules graphics
You can send in your Node projects for review through our contact form.

0.9.8

Node 0.9.8 is out. This release includes an interesting patch from Jake Verbaten to support arbitrary objects in streams. Internally, streams now switch to objectMode when objects are detected. The unit tests illustrate how this works in practice:

test('can read objects from stream', function(t) {
  var r = fromArray([{ one: '1'}, { two: '2' }]);
  var v1 = r.read();
  var v2 = r.read();
  var v3 = r.read();

  assert.deepEqual(v1, { one: '1' });
  assert.deepEqual(v2, { two: '2' });
  assert.deepEqual(v3, null);
  t.end();
});

Notice how each read causes an object to be returned. Jake has been heavily involved with streams over the last year or two, with plenty of notable modules in his Raynos GitHub account.

Queen

Queen

Last week I wrote about Ozan Turgut’s Thrill project. The core component, which people seemed to find more interesting, was Queen (GitHub: turn / queen, License: Apache v2, npm: queen). Queen is a server that can run scripts on multiple browsers. This could be used for anything, not just for running tests which is what Thrill does.

Queen clients and servers have bidirectional communication, and Queen will detect and recover unresponsive browsers. It can target browsers by type, version, and OS, and run scripts via the command-line.

AssetViz

AssetViz on DailyJS

AssetViz (GitHub: Munter / assetviz, License: MIT, npm: assetviz) by Peter Müller is a command-line web application source code visualisation tool. It generates self-contained HTML files that show a visualisation of the site using D3.js.

The nodes that make up the visualisation can be dragged and will spring back into place, and you can also zoom using the mousewheel.

jQuery Roundup: QUnit 1.11, Knockout-jQueryUI, Tab Override, FilteredPaste.js

29 Jan 2013 | By Alex Young | Comments | Tags jquery plugins testing knockout keyboard paste
Note: You can send your plugins and articles in for review through our contact form.

QUnit 1.11

There’s a good post on the official jQuery blog about a change in direction to the QUnit project: QUnit 1.11 Release: A Look Back (and Forth). It discusses some of the history behind QUnit, and includes a survey where you can share how you’re using it.

Knockout-jQueryUI

Trying to integrate libraries like Knockout is sometimes confusing when you’re already using jQuery UI. To address this, Vas Gábor has created Knockout-jQueryUI (GitHub: gvas / knockout-jqueryui, License: MIT), which is a collection of Knockout bindings for jQuery UI widgets.

It’s small, comes with a build script and unit tests, and the author has provided full documentation on the project’s homepage.

Tab Override

Tab Override (GitHub: wjbryant / taboverride, License: MIT, bower: taboverride) by Bill Bryant allows the tab key to insert tabs in textarea elements. It also supports auto indent and multi-line tab insertion.

There’s also a jQuery Tab Override plugin, and both scripts are AMD-compatible. Bill has included QUnit tests, which actually simulate key presses to test the script’s various features.

FilteredPaste.js

FilteredPaste.js (GitHub: willemmulder / FilteredPaste.js, License: CC BY-SA 3.0) by Willem Mulder can be used to filter text when it’s pasted into textarea elements, or anything with the contenteditable attribute. Why is this useful? Well, Willem got tired of dealing with support requests when text pasted from Word into his CMS carried across unwanted formatting.

I find myself always using Paste and Match Style and wondering why this isn’t the default for the paste keyboard shortcut. The only time I’ve ever wanted to include formatting when pasting is when I make slides in Keynote/PowerPoint/Google Drive and want to include syntax highlighting in my examples. And that seems like an edge case if ever there was one!

Confused About Components

28 Jan 2013 | By Alex Young | Comments | Tags component.json package-management

Client-side development has been shifting away from monolithic libraries. While jQuery is still hugely popular, building projects from smaller libraries is increasingly common. To make this easier to deal with, projects have appeared to manage dependencies. These tools may be simple package managers, or a combination of a build tool and a package manager.

Recent History

Client-side package managers have been around for a few years now. An earlier example is CPM, which is a CommonJS package manager. Last year the subject got newfound attention from Node developers. There was a very public debate between Isaac Schlueter and TJ Holowaychuk in which several issues were covered:

  • Should client-side libraries use CommonJS modules or AMD?
  • Should npm or a new registry be used to store client-side libraries?
  • What should be included within client-side libraries?

“A component can be not just JavaScript, but CSS, images, fonts or other resources, or a component may be any combination of these. This is the main idea that I want to sell, we need to broaden modularity beyond just JavaScript source.”

TJ Holowaychuk, Components

“However, they should have the same level of modularity and order that we’ve been able to get with JavaScript packages using npm and Node.js. It’s a much stickier problem, because the deployment environment is so much more hostile.”

Isaac’s response

Shortly after this discussion, TJ released Component, which is a component manager. Components may include JavaScript, styles, and markup. Markup and styles are encouraged to be “structural”, allowing users to easily skin components. Examples of components include anything from generic JavaScript libraries – like a small mathematical helper function, to a fully-blown UI widget, like a date picker.

Component Workflows

What isn’t immediately obvious about Component is it builds client-side scripts by adding a CommonJS Modules/1.1 implementation – components are loaded using var lib = require('lib'). The upshot of this is there’s a learning curve to writing components, and also understanding how to make this work inside existing projects. Component is specifically designed to work regardless of server-side architecture, so you could use it with Django, Express, or Rails projects without special handling. Discovering how to use components inside these frameworks is the main point of friction when switching to a component-based workflow – do you structure your entire project around components? Or just use Component as a way of managing dependencies?

Contrast this to Bower. It’s more like earlier projects, which include Jam and Volo, and therefore offers less in terms of treating entire slices of the UI as reusable chunks. This is by design – Bower is meant to work with build tools rather than replace them.

Then there’s Ender, which provides an API for loading modules (CommonJS is supported), and is built on top of npm. Jam encourages the use of AMD and depends on RequireJS. Volo doesn’t depend on AMD modules, but encourages them to be used.

Bower could have effectively been: curl http://wherever-bower-repos-are.com | grep underscore | xargs git clone

TJ Holowaychuk, component Google Group

That’s how I initially felt when I first saw Bower, but Bower’s simplicity is a result of it being designed to work alongside client-side build tools. That means Bower will work with RequireJS, LoadBuilder, or even Sprockets. If you’re using a large server-side framework like Rails, then it might be easier to use Bower with the framework’s existing asset management tools.

Build Tools and Package Managers

As TJ hinted at above, the biggest problem facing client-side package managers is anybody can make one. It doesn’t take much effort to write a script that can fetch libraries from GitHub and then pipe them through UglifyJS.

Bower’s separation between package manager and build tools is insightful, but I also think the modular client-side development being pushed by Component is extremely important and makes client-side development better.

The State of Affairs

We’re now at the point where library authors are increasingly including a component.json file. How do you know if this is a Bower or Component manifest file? Let’s say I want to install pjax. It has a component.json, so I run component install defunkt/jquery-pjax. The result is an error:

error : Error: invalid component name "jquery"

It turns out pjax is designed to be used with Bower.

This situation is made more confusing because neither project addresses this fact. It’s almost like they don’t want to acknowledge each other. There’s a discussion about Bower in the component Google Group, but neither project is particularly helpful with regard to the differences between manifest files, given the decision to use the same name.

Is Bower run by evil Twitter imperialists hell-bent on wrestling component.json away from the Component project? Well, no, because Bower can be configured to use a different file name, and the projects have different goals. However, the clash is unfortunate, particularly for client-side developers who work closer to the design end of the design/coding spectrum, and may not even be aware that both projects exist.

It would be nice to see this issue addressed clearly in Bower and Component’s documentation. The fact Twitter has its logo on Bower doesn’t make it the best or correct project to use – I encourage you to try out both projects. Client-side development is more than just JavaScript files, so I feel like Component has a chance to reach critical mass if enough people get behind it.

Jargon

  • Package Manager: Fetch scripts from online sources like GitHub, taking dependencies into account.
  • Build Tool: Combine scripts and other assets together into something usable by browsers.
  • Module System: A way to programmatically load scripts when they’re needed.

Comparison Table

  Bower Component Ender Jam Volo
License MIT MIT MIT MIT MIT/New BSD
Appeared Sep 2012 Aug 2012 Apr 2011 May 2012 Oct 2010
Package Registry Server Wiki npm Server GitHub
Module Pattern   CommonJS CommonJS AMD AMD/CommonJS compatible

pde-engine, colormap, Dimsum

25 Jan 2013 | By Alex Young | Comments | Tags libraries graphics physics node modules fastfood

pde-engine and colormap

Wave example running on benpostlethwaite.ca

Ben Postlethwaite sent in two libraries this week. The first, pde-engine (GitHub: bpostlethwaite / pde-engine, License: MIT, npm: pde-engine), can be used to create “nice looking physically realistic effects in websites or games”.

Ben’s site, benpostlethwaite.ca has live examples for the “wave” and “heat” equations, and the project takes advantage of Typed Arrays to improve performance. Ben suggests using browserify to generate a browser-friendly version of code using pde-engine.

The colours in Ben’s examples come from his second project, colormap (GitHub: bpostlethwaite / colormap, License: MIT, npm: colormap). This project generates color values based on Matlab’s plot colours, and apparently works well with D3.js.

Both projects come with example code and documentation in the readme files.

Dimsum

I don’t mind a bit of dim sum now and again, particularly those steamed buns with custard fillings. My computer can’t yet 3D print Chinese dumplings though, so instead I recommend Dimsum (GitHub: ninjascribble / dimsum, License: MIT, npm: dimsum) by Scott Grogan. It generates lorem ipsum text, and can be used with Node or browsers.

Dimsum includes two flavours: latin and jabberwocky. New flavours can also be added, so you could dump in some generic marketing text to get a more accurate mockup going.

Scott has thoughtfully included Mocha tests as well.

Backbone.js Tutorial: Tasks

24 Jan 2013 | By Alex Young | Comments | Tags backbone.js mvc node backgoog fastfood

Preparation

Before starting this tutorial, you’ll need the following:

  • alexyoung / dailyjs-backbone-tutorial at commit 8d88095
  • The API key from part 2
  • The “Client ID” key from part 2
  • Update app/js/config.js with your keys (if you’ve checked out my source)

To check out the source, run the following commands (or use a suitable Git GUI tool):

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 8d88095

Tasks CRUD

Things have been quiet in the Tasks Bootstrap project over the last few weeks. Lists have appeared, but there’s been nary a Hamburglar or Burger King in sight. How do we attract those all important fast food mascots to our project? By adding support for tasks of course! How else can they write their extensive lists of upcoming franchise inspections and special edition McRibs?

This tutorial will cover the following:

  • Creating a view for a single task
  • Creating a view for a list of tasks
  • Adding the tasks collection
  • Fetching tasks from Google’s API

The really interesting part that you’ll want to remember is dealing with the relationship between a parent view and child views. Backbone doesn’t specifically address relationships between models, or views. In this example, we ideally want to say tasks belong to lists or task views belong to list views. However, there isn’t a de facto way of expressing such relationships. There are libraries out there to do it, but I’ll show you how to think about things in pure Backbone/Underscore.

Boilerplate

Before you get started, create some new directories:

$ mkdir app/js/views/tasks
$ mkdir app/js/templates/tasks

And add a new collection to app/js/collections/tasks.js:

define(['models/task'], function(Task) {
  var Tasks = Backbone.Collection.extend({
    model: Task,
    url: 'tasks'
  });

  return Tasks;
});

The Tasks collection doesn’t do anything you haven’t seen before. Fetching tasks with Google’s API requires a tasklist, so you have to call fetch with an additional parameter:

collection.fetch({ data: { tasklist: this.model.get('id') }, // ...

It’s cool though, because we handled fetching TaskLists like that when we passed { userId: '@me' } so it feels consistent within the context of this project.

The template that contains the tasks view includes a form for creating new tasks, a container for the task list, and another container for the currently selected task (so it can be edited). This file should be saved as app/js/templates/index.js:

<div class="span6">
  <div id="add-task">
    <form class="well row form-inline add-task">
      <input type="text" class="pull-left" placeholder="Enter a new task's title and press return" name="title">
      <button type="submit" class="pull-right btn"><i class="icon-plus"></i></button>
    </form>
  </div>
  <ul id="task-list"></ul>
</div>
<div class="span6">
  <div id="selected-task"></div>
  <div class="alert" id="warning-no-task-selected">
    <strong>Note:</strong> Select a task to edit or delete it.
  </div>
</div>

This uses some Bootstrap classes for creating columns. The TaskView, in app/js/templates/tasks/task.html has a few elements to contain the title, notes, and a checkbox for toggling the task’s state:

<input type="checkbox" data-task-id="" name="task_check_" class="check-task" value="t">
<span class="title "></span>
<span class="notes"></span>

Views

The main TasksIndexView loads the tasks using the Tasks collection, and then renders them using TaskView. This is the source for TasksIndexView in app/js/views/tasks/index.js:

define(['text!templates/tasks/index.html', 'views/tasks/task', 'collections/tasks'], function(template, TaskView, Tasks) {
  var TasksIndexView = Backbone.View.extend({
    tagName: 'div',
    className: 'row-fluid',

    template: _.template(template),

    events: {
      'submit .add-task': 'addTask'
    },

    initialize: function() {
      this.children = [];
    },

    addTask: function() {
    },

    render: function() {
      this.$el.html(this.template());

      var $el = this.$el.find('#task-list')
        , self = this;

      this.collection = new Tasks();
      this.collection.fetch({ data: { tasklist: this.model.get('id') }, success: function() {
        self.collection.each(function(task) {
          var item = new TaskView({ model: task, parentView: self });
          $el.append(item.render().el);
          self.children.push(item);
        });
      }});

      return this;
    }
  });

  return TasksIndexView;
});

This loads the tasks using collection.fetch, and then appends a TaskView for each task. This is TaskView:

define(['text!templates/tasks/task.html'], function(template) {
  var TaskView = Backbone.View.extend({
    tagName: 'li',
    className: 'controls well task row',

    template: _.template(template),

    events: {
      'click': 'open'
    },

    initialize: function(options) {
      this.parentView = options.parentView;
    },

    render: function(e) {
      var $el = $(this.el);
      $el.data('taskId', this.model.get('id'));
      $el.html(this.template(this.model.toJSON()));
      $el.find('.check-task').attr('checked', this.model.get('status') === 'completed');

      return this;
    },

    open: function(e) {
      if (this.parentView.activeTaskView) {
        this.parentView.activeTaskView.close();
      }
      this.$el.addClass('active');
      this.parentView.activeTaskView = this;
    },

    close: function(e) {
      this.$el.removeClass('active');
    }
  });

  return TaskView;
});

The parent view is tracked so open can determine if another task has been clicked on, and if so “deactivate” it (remove the active class). There are many ways to do this: I’ve seen people iterating over views to close all of them, using $('selector').removeClass('active') to remove all related items with an active class, or triggering events on models. I feel like view-related code should be handled in views, and models and collections should do their own specific jobs.

Next you’ll need to add TasksIndexView to the define in app/js/views/lists/menuitem.js and change the open method to instantiate a TasksIndexView:

open: function() {
  if (bTask.views.activeListMenuItem) {
    bTask.views.activeListMenuItem.$el.removeClass('active');
  }

  bTask.views.activeListMenuItem = this;
  this.$el.addClass('active');

  // Render the tasks
  if (bTask.views.tasksIndexView) {
    bTask.views.tasksIndexView.remove();
  }

  bTask.views.tasksIndexView = new TasksIndexView({ collection: bTask.collections.tasks, model: this.model });
  bTask.views.app.$el.find('#tasks-container').html(bTask.views.tasksIndexView.render().el);

  return false;
}

It tracks the last instance of TasksIndexView so it can remove it manually. It’s usually a good idea to call remove so events can be unbound before views go out of scope – I’ll write a tutorial about Backbone and garbage collection later on.

I also added some defaults to the Task model (in app/js/models/task.js):

define(function() {
  var Task = Backbone.Model.extend({
    url: 'tasks',
    defaults: { title: '', notes: '' }
  });

  return Task;
});

The reason I did this was the TaskView will raise errors when interpolating using a model that doesn’t have a title or notes – it’s quite common for tasks in Google Tasks to not have any notes.

With these templates, views, and changes, you should be able to select lists and see their tasks, and also select tasks.

Styles

Bootstrap styles

As it stands, the application doesn’t make a lot of visual sense. I’ve added Bootstrap – this just required downloading the CSS and image files and putting them in app/css and app/img. Also, app/index.html loads css/bootstrap.min.css.

I added some custom styles to create a panel-based layout that shows the tasks in a similar way to Things.

Backbone 0.9.10

I’ve updated Backbone to 0.9.10 and added it to the repository. I had to change the Backbone.sync method to use a different signature when calling options.success, in app/js/gapi.js:

options.success(model, result, request);

Summary

The full source for this tutorial can be found in alexyoung / dailyjs-backbone-tutorial, commit 0491ad.

Node Roundup: 0.8.18, Thrill, analytics-node, Hulkster

23 Jan 2013 | By Alex Young | Comments | Tags node modules testing templating
You can send in your Node projects for review through our contact form or @dailyjs.

Node 0.8.18

Node 0.8.18 is out, and 0.9.7 was released on the same day as well.

I’m still tracking those stream module changes in the 0.9 branch, and this release has a fix for handling large reads from push-streams. Although the commit isn’t dramatic, the test case seems to thoroughly cover the problems outlined in the commit message.

Thrill

Thrill

Ozan Turgut sent in Thrill (GitHub: ozanturgut / thrill, License: Apache 2.0, npm: thrill), a new test runner that can drive browsers over the network. A server runs tests using pools of browsers powered by Selenium Grid, Sauce Labs, or Browser Stack.

There’s a quick start guide that explains how to install the requirements and run some tests using Jasmine, but you could use another test framework if you prefer.

The tests will be run in a browser after “connecting” it to a server. Once this is done, tests can be run using the command-line tool, thrill. That means you can run a standard Jasmine spec file with thrill runner.html and it’ll run on all of the connected browsers.

The documentation for the project makes all of this easy to follow, so if you want to try it out take a look at taht quick start guide.

analytics-node

analytics-node (GitHub: segmentio / analytics-node, License: MIT, npm: analytics-node) is a Node client for Segment.io. It can be used to send data to various analytics services with the same API as the extremely popular analytics.js library.

Hulkster

Hulkster (GitHub: neoziro / hulkster, License: MIT, npm: hulkster) by Greg Bergé is a Hogan.js wrapper that adds extra functionality. It can be used as a Node module, or as a command-line tool.

Hulkster adds lots of command-line options, like control over the format (json or js), the export variable used, AMD-style, and minification. The author has included some Mocha tests to make sure these new features work as intended.

jQuery Roundup: Plugin Registry, imagemax, jQuery Sortable

22 Jan 2013 | By Alex Young | Comments | Tags jquery plugins sortable galleries slideshow
Note: You can send your plugins and articles in for review through our contact form or @dailyjs.

jQuery Plugin Registry

jQuery: Write once, do more, then write a weird framework-specific manifest file, learn Git, then share!

The new jQuery Plugin Registry has finally been released. It’s based on WordPress, and you can download the source from GitHub: plugins.jquery.com.

To list a plugin on the registry, take a look at the Publishing Your Plugin guide. The workflow is based around Git, and you’ll need to write a jquery.json manifest file so the registry can display appropriate metadata. Even though dependencies are listed, there isn’t an official automated tool for installing them (a jQuery npm or component equivalent):

If you’re looking to just browse and use jQuery plugins in your application or site, not a lot has changed. Plugins each have basic pages that provide a link to the plugin download, as well as past versions, documentation, issue tracker, and source code repository. Download links may serve you a zip file with the plugin assets, or link to the best resource to download the build of the plugin you’re looking for.

Given the amount of people writing JavaScript libraries with an optional jQuery support layer, having to add an extra file just to get published on a website seems odd to me. While it means you don’t need to create an account on the plugin registry site, people will end up with several json files littering their repositories and getting out of sync. There’s probably already a Node tool for automatically generating jQuery, Component/Bower, and npm/Ender json files.

imagemax

imagemax (GitHub: zerostatic / imagemax, License: MIT) by Matt Wallace is a fullscreen slideshow plugin. Images are displayed in the background and scaled to fit the window.

Like other gallery plugins, this one will display a set of images in a container, but it also takes an array of images as an argument:

$('#bg').imagemax({
  imageArray: ['img/bg1.jpg','img/bg2.jpg','img/bg3.jpg']
, autoPlay: 4000
});

jQuery Sortable

jQuery Sortable (GitHub: johnny / jquery-sortable, License: BSD3) by Jonas von Andrian is a drag-and-drop sort library that doesn’t require jQuery UI. It supports nested lists, and the demo (with default options) shows a nice “drop” indicator so it’s easy to see where an element is being moved to.

The author has demonstrated it being used with Bootstrap, and it works well with Bootstrap’s markup and styles. It allows tables to be sorted, but this won’t work as well in Konqueror or IE.

Caress, cjs2web, zoe.js

21 Jan 2013 | By Alex Young | Comments | Tags libraries oo touch commonjs

Caress

Caress (GitHub: ekryski / caress-server, License: MIT, npm: caress-server) by Eric Kryski converts TUIO events to browser events (W3C Touch Events version 2), allowing desktop browsers to be driven by multitouch devices. This includes Apple’s Magic Trackpad, Android, and iOS devices.

Caress uses Node and Socket.IO to send TUIO messages to the browser – this is usually done using UDP, but Node and Socket.IO seem to work well. Since Caress can be used with the Magic Trackpad, it might work well as a shortcut for testing touch-based interfaces during development.

cjs2web

cjs2web (GitHub: cjs2web, License: MIT, npm: cjs2web) by Alex Lawrence is a CommonJS module-to-browser translation tool. It currently supports mapping local modules, and the exports object (including module.exports). It doesn’t support Node’s process and global modules, so it’s useful for lightweight porting of browser-friendly code. This is in contrast to something like OneJS that actually aims to create a Node-like environment in the browser.

Jasmine specs are included, and the Grunt build script used to run them.

zoe.js

zoe.js (GitHub: zestjs / zoe, License: MIT, npm: zoe, component: zestjs/zoe) by Guy Bedford is a Node/AMD/browser library for working with multiple inheritance:

The basic principle is that inheritance is a form of object extension. A core object is extended with a number of implemented definitions. When that object is extended, a new object is created implementing the core definitions as well as any new definitions. This is the inheritance system of zoe.create.

Objects created this way can be configured with “function chains”, which allows the library to support asynchronous code and various forms of the observer pattern.

Basic object extension uses zoe.create:

var baseClass = {
  hello: 'world'
};

var derivedClass = zoe.create([baseClass], {
  another: 'property'
});

If an _extend property is supplied, zoe will use it to apply various rules. In this example, chaining is used which will cause both greet methods to run:

var greetClass = {
  _extend: {
    greet: 'CHAIN'
  },
  greet: function() {
    return 'howdy';
  }
};

var myClass = zoe.create([greetClass], {
  greet: function() {
    alert('greeting');
  }
});

myClass.greet();

BreezeJS, Automaton, dejavu

18 Jan 2013 | By Alex Young | Comments | Tags libraries oo databases

BreezeJS

BreezeJS (GitHub: IdeaBlade / Breeze, License: MIT) by IdeaBlade is a data management library – it can be used to build queries, track changes, bind to MVC libraries like Knockout, and cache data in the client.

The query interface is like LINQ, but it doesn’t specifically require .NET:

var query = breeze.EntityQuery
           .from('Customers')
           .where('CompanyName', 'startsWith', 'A')
           .orderBy('CompanyName');

BreezeJS supports asynchronous queries through promises:

var promise = manager.executeQuery(query)
              .then(querySucceeded)
              .fail(queryFailed);

Although it’s open source, the company behind it has commercial support packages. There are also BreezeJS tutorials for getting started. It can work with various SQL and NoSQL databases – the nature of this and the relationship to the .NET Entity Framework is explained in the BreezeJS FAQ (before complaining about .NET in the comments read the FAQ first).

Automaton

Automaton (GitHub: IndigoUnited / automaton, License: MIT, npm: automaton) from Indigo United is a task automation tool, similar to Grunt but (from what I can gather) the way tasks are reused works differently.

It’s designed to be used with Node and installed through npm, and it has an API for programatically running tasks. The documentation is good, and it makes it clear what parts of the API use streams or other things you can easily hook into with Node.

dejavu

dejavu

dejavu (GitHub: IndigoUnited / dejavu, License: MIT, npm: dejavu) also from Indigo United is a classical OO toolkit that can be used with browsers or Node. It can work with AMD, and in that case the syntax reminds me of Backbone projects written using RequireJS.

It supports the usual features: classes, inheritance, mixins, private and protected members, and also adds some type checking tools like method signature checks and a custom instanceOf. The authors have provided benchmarks, which is good, because I’ve seen too many libraries that say they’re fast without any proof.

After writing JS101, which has some coverage of working with prototypes and JavaScript objects in general, seeing “classical OO” libraries makes me extremely wary. However, I’ve given dejavu a cursory look, and it includes Mocha tests, and takes a wide range of influences into account, so it might be worth adding to your microjs/component library bookmarks for the next time you really need some of the features this library provides. I thought the name “dejavu” was a nod to the plethora of similar libraries out there, but I think it refers to the fact it looks more like OO in other languages.

Backbone.js Tutorial: Deleting Lists

17 Jan 2013 | By Alex Young | Comments | Tags backbone.js mvc node backgoog

Preparation

Before starting this tutorial, you’ll need the following:

  • alexyoung / dailyjs-backbone-tutorial at commit 0953c5d
  • The API key from part 2
  • The “Client ID” key from part 2
  • Update app/js/config.js with your keys (if you’ve checked out my source)

To check out the source, run the following commands (or use a suitable Git GUI tool):

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 0953c5d

Deleting Lists

We’re now at the end of the complete CRUD implementation for lists. To support deleting items, we just need to hook up the link that we’ve already added and add support for the delete method to gapi.js. You could try doing this yourself for practice.

Open app/js/views/app.js, and add an event binding for the “Delete List” link:

events: {
  'click #add-list-button': 'addList'
, 'click #edit-list-button': 'editList'
, 'click #delete-list-button': 'deleteList'
},

Next, add a method called deleteList to the same class:

deleteList: function() {
  if (confirm('Are you sure you want to delete that list?')) {
    bTask.views.activeListMenuItem.model.destroy();
  }
  return false;
}

Just by making those two changes, the active list will be removed from the interface. Backbone knows how to remove the view when model.destroy is called in deleteList.

Backbone.sync Changes

To persist deleting lists, open app/js/gapi.js and add a case for 'delete' after 'update' (it should be around line 100):

case 'delete':
  requestContent['resource'] = model.toJSON();
  request = gapi.client.tasks[model.url].delete(requestContent);
  Backbone.gapiRequest(request, method, model, options);
break;

Google’s API provides the delete method, otherwise this is identical to the implementation for updating items.

Next

This part was short, so consider this your week off. Go and play with the source and see what you can get the Google Tasks API and Backbone to do! There’s still a lot of things left to cover, however.

Over the last eight weeks you’ve learned how to:

  • Write a custom Backbone.sync method
  • Use the Google Task API with client-side JavaScript
  • Write Backbone models, views, and collections

This could be adapted to work with other Google APIs, or potentially even other APIs that I haven’t considered. Once you have a solid understanding of how Backbone models and syncing data works, then a lot becomes possible.

The next few parts will cover the following:

  • Mocking the Google Tasks API for testing
  • Adding, editing, and deleting the tasks themselves
  • A Bootstrap user interface
  • Customising Bootstrap

Summary

The full source for this tutorial can be found in alexyoung / dailyjs-backbone-tutorial, commit 8d88095.

Node Roundup: 0.8.17, 0.9.6, gelf-node, jsong, Stuff.js

16 Jan 2013 | By Alex Young | Comments | Tags node modules unix cli json sandbox search
You can send in your Node projects for review through our contact form or @dailyjs.

Node 0.8.17, 0.9.6 (Unstable)

Node 0.8.17 was released last week with a security fix for TypedArrays, so you should upgrade if you’re using them:

If user input can affect the size parameter in a TypedArray, an integer overflow vulnerability could allow an attacker to write to areas of memory outside the intended buffer.

The unstable branch also saw a new release with 0.9.6. The streams API has changed slightly again as it continues to be developed: Isaac Schlueter added the readable.push method, and there are also fixes for TypedArrays in this branch too.

gelf-node

I’ve had a lot of luck with ElasticSearch. The last time I used it was on a project that used Node HTTP crawlers to index thousands of sites, and it was all backed by ElasticSearch. It worked extremely well and I actually got paid! If you’re also using ElasticSearch, then you might be interested in the gelf-node module (GitHub: robertkowalski / gelf-node, License: MIT, npm: gelf) by Robert Kowalski. It works with Graylog2, allowing messages to be sent from Node:

var Gelf = require('gelf');
var gelf = new Gelf({
  graylogPort: 12201,
  graylogHostname: '127.0.0.1',
  connection: 'wan',
  maxChunkSizeWan: 1420,
  maxChunkSizeLan: 8154
});

// The readme has an example message
gelf.emit('gelf.log', message);

Graylog2 itself is released under the GPL (version 3).

jsong

jsong (GitHub: textgoeshere / jsong, npm: jsong, License: MIT) by Dave Nolan is a CLI tool and module for filtering JSON. It’s built with streamin and clarinet, and shows full paths to matches:

$ cat my.json | jsong -k 'z\wp'

foo.bar.zip: val1
foo.bar.zap: val2
quux.zip: val

Because it’s built using streams, it should handle large JSON files.

Stuff.js

Here’s another project by Amjad Masad from Codecademy: Stuff.js (GitHub: Codecademy / stuff.js, License: MIT) – an easy way to run arbitrary HTML and JavaScript in an iframe. It uses node-static and uglify-js to create a sandbox for securely running user-contributed code.

There’s an example in Amjad’s blog post that shows how to use it:

stuff(secureIframeUrl, function (context) {
  var html = CodeMirror.fromTextArea($('#html'), {
    onChange: reload
  , mode: 'text/html'
  });
  var js = CodeMirror.fromTextArea($('#js'), {
    onChange: reload
  , mode: 'javascript'
  });
  var css = CodeMirror.fromTextArea($('#css'), {
    onChange: reload
  , mode: 'css'
  });

  var t = null;
  function reload () {
    clearTimeout(t);
    t = setTimeout(function () {
      var code = '<!DOCTYPE html><html><head>';
      code += '<style>'  + css.getValue() + '</style>';
      code += '<body>' + html.getValue();
      code += '<script>' + js.getValue() + '</script>';
      code += '</body></html>';
      context.load(code);
    }, 50);
  }
  reload();
});

jQuery Roundup: 1.9, Touch-box, Elevate Zoom, textareaHelper

15 Jan 2013 | By Alex Young | Comments | Tags jquery plugins images zoom touchscreen textarea
Note: You can send your plugins and articles in for review through our contact form or @dailyjs.

jQuery 1.9

jQuery 1.9 has been released. This version retains legacy browser support, but “slims down” the API somewhat. jQuery 2.0 meanwhile will not support Internet Explorer 6-8, but it will have the same API.

jQuery Migrate can be used to migrate to 1.9 or 2.0.

Touch-box

Dannie Hansen sent in Touch-box (GitHub: danniehansen / Touch-box, License: GPL), a plugin for resizing and dragging elements on touchscreen devices. Although the documentation mentions iPad, I tested it on Android Chrome and both seemed to work well.

Dannie suggested an interesting idea for a gallery, where the resize event could automatically cause higher resolution images to be fetched through a callback:

$('.box').TouchBox({
  resize: true,
  drag: true,
  callback_touches: function(touches) {
  },
  callback_change: function() {
  }
});

Elevate Zoom

Elevate Zoom's tint feature.

Elevate Zoom (GitHub: elevateweb / elevatezoom, License: MIT/GPL) by Andy Eades is an image zoom plugin that has FancyBox support. It has some cool features like “tinting”, where the unzoomed portion of the image is tinted – demos are available for each of the main features.

textareaHelper

textareaHelper by Amjad Masad and Codecademy transparently copies a textarea’s contents into a div, so it can be manipulated in ways not supported by textarea. It will try to copy the styles from the textarea as well, and can fetch the caret’s position.

Mocha tests have been included, which includes a setSelectionRange implementation to test the caret handling.

Framer, ModelFactory, Mongo Edit

14 Jan 2013 | By Alex Young | Comments | Tags testing backbone.js mongodb
Note: You can send your plugins and articles in for review through our contact form or @dailyjs.

Framer

Framer

Framer (GitHub: koenbok / Framer, License: MIT) by Koen Bok is a prototyping tool aimed at designers who can write basic JavaScript. It uses hardware acceleration and a simple JavaScript API for working with a subset of view types that are reminiscent of the ones used in Apple’s iOS frameworks.

The example on the site creates the iPhone container view, so you could adapt it to show something else if you wanted. The author suggests using Framer in conjunction with Cactus and Ratchet for creating rapid prototypes of iOS applications.

Backbone.ModelFactory

Backbone.ModelFactory (License: MIT) by Pat O’Neill generates model constructors that never produce multiple instances of a model with the same unique identifier. This is intended to make sharing models between views easier. This steps around Backbone’s built-in behaviour, and was based on Building the Next SoundCloud – an internal cache of model instances can be created based on their IDs:

Almost all views are instantiated only with the id of its model, so it’s quite possible that the data for that model hasn’t been loaded yet. To solve this, we use a construct we call the instance store. This store is an object which is implicitly accessed and modified each time a constructor for a model is called. When a model is constructed for the first time, it injects itself into the store, using its id as a unique key. If the same model constructor is called with the same id, then the original instance is returned.

Mongo Edit

Mongo Edit (License: MIT, npm: mongo-edit) from tldr.io is a simple editor for data in MongoDB. It’s built with Express, and the ACE editor.

If you’re looking for examples of Express applications, this one is built with route separation, and includes some simple Mocha tests.

Catalyst, Teacup, Makery

11 Jan 2013 | By Alex Young | Comments | Tags sponsored-content testing templates
Note: You can send your plugins and articles in for review through our contact form or @dailyjs.

Catalyst

Catalyst

Learning JavaScript? Join Catalyst! Full-time, in-person training and job placement services over 12 weeks in San Francisco. Instructors and speakers from Twitter, OkCupid, Adobe, Meteor, and more.

For more information, visit catalystclass.com.

Teacup

Teacup (GitHub: goodeggs / teacup, License: MIT, npm: teacup) by Good Eggs is a CoffeeScript templating language. It comes with middleware that can be used alongside connect-assets for compiling the templates, and the language kind of reminds me of CoffeeScript crossed with Jade:

{renderable, js, css, html, head, body} = require 'teacup'

module.exports = renderable ->
  html ->
    head ->
      js 'app'
      css 'app'
    body ->
      # ...

It works in browsers, has Mocha tests, and also has a gem for Rails: Teacup::Rails. The author wrote a blog post about it here: Teacup: CoffeeScript Templates for Developer Happiness.

Makery

Makery (License: MIT, npm: makery) by Leonardo Garcia Crespo is a module for making objects to aid with testing – the author says it works well for testing Backbone models. The API looks like this:

Makery.blueprint(MyConstructor, function() {
  return {
    id: this.unique(),
    aProperty: 'Some value',
    anotherProperty: 'Another value'
  };
});

var obj = MyConstructor.make();

Jasmine tests have been included, and it can be used in browsers as long as Underscore is present.

Backbone.js Tutorial: Editing Lists

10 Jan 2013 | By Alex Young | Comments | Tags backbone.js mvc node backgoog

Preparation

Before starting this tutorial, you’ll need the following:

  • alexyoung / dailyjs-backbone-tutorial at commit 465523f
  • The API key from part 2
  • The “Client ID” key from part 2
  • Update app/js/config.js with your keys (if you’ve checked out my source)

To check out the source, run the following commands (or use a suitable Git GUI tool):

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 465523f

Active List

Last week I demonstrated how to make a custom Backbone.sync “create” implementation, and suitable views and templates for adding new lists. If you recall, I created a view for editing lists as well, because it was so similar to AddListView it made sense to inherit from it.

Before a list can be edited, we need a way of selecting lists. It makes sense to always have an active list in this application, so there should be a way of saving this state somewhere. Also, when loading the lists from the server, a default list should be selected on the user’s behalf.

To be consistent with the patterns employed to track collections and views, we should add a models object for tracking instances of models. One of these can be the activeList.

Open app/js/app.js and add a models property as well as setting the activeModel after the lists have loaded:

App.prototype = {
  views: {},
  collections: {},
  models: {},
  connectGapi: function() {
    var self = this;
    this.apiManager = new ApiManager(this);
    this.apiManager.on('ready', function() {
      self.collections.lists.fetch({ data: { userId: '@me' }, success: function(res) {
        self.models.activeList = self.collections.lists.first();
        self.views.listMenu.render();
      }});
    });
  }
};

Now open app/js/views/lists/menu.js and make it check if the activeModel is the model currently being used to render the navigation list element:

renderMenuItem: function(model) {
  var item = new ListMenuItemView({ model: model });
  this.$el.append(item.render().el);

  if (model.get('id') === bTask.models.activeList.get('id')) {
    item.open();
  }
},

If the model does match, then it’ll trigger an open on the view. Now open app/js/views/lists/menuitem.js and make the ListMenuItemView track the activeModel:

open: function() {
  bTask.models.activeList = this.model;
  return false;
}

Now the application is able to track the selected list. This will make adding tasks easier, because in order to add tasks we need to know which tasklist to add it to.

Edit List Form

Open app/js/views/app.js. The goal of this exercise is to make the edit form appear, filled out with the correct values, when the “Edit List” link is clicked. It’s going to be similar to last week’s addList method, so you can try doing this part yourself if you want.

First, make it load the EditListView class:

define([
  'text!templates/app.html'
, 'views/lists/add'
, 'views/lists/edit'
],

function(template, AddListView, EditListView) {

Next, add the #edit-list-button to the events:

events: {
  'click #add-list-button': 'addList'
, 'click #edit-list-button': 'editList'
},

Finally, add the editList method to instantiate an EditListView form based on the activeList:

editList: function() {
  var form = new EditListView({ model: bTask.models.activeList });

  this.$el.find('#list-editor').html(form.render().el);
  form.$el.find('input:first').focus();

  return false;
}

This is very similar to the addList method – they could easily use the same method, just with different models:

listForm: function(form) {
  this.$el.find('#list-editor').html(form.render().el);
  form.$el.find('input:first').focus();

  return false;
},

addList: function() {
  return this.listForm(new AddListView({ model: new bTask.collections.lists.model({ title: '' }) }));
},

editList: function() {
  return this.listForm(new EditListView({ model: bTask.models.activeList }));
}

DRY!

Saving Changes

The Backbone.sync method needs to be updated to cope with updating items. This is very similar to creating items (in app/js/gapi.js):

// Around line 97, after 'create'
case 'update':
  requestContent['resource'] = model.toJSON();
  request = gapi.client.tasks[model.url].update(requestContent);
  Backbone.gapiRequest(request, method, model, options);
break;

A slight complication is Google’s API requires a tasklist property in the object passed to update. This isn’t very clearly documented (you’ll notice the tasklists/update reference doesn’t have a JavaScript example).

Rather than making the Backbone models somehow aware of this, it’s better to put the logic in Backbone.sync. That way all of the Google-related stuff is in the same place.

Add another switch statement to insert the required ID parameters, based on the type of model being operated on:

Backbone.sync = function(method, model, options) {
  var requestContent = {};
  options || (options = {});

  switch (model.url) {
    case 'tasks':
      requestContent.task = model.get('id');
    break;

    case 'tasklists':
      requestContent.tasklist = model.get('id');
    break;
  }

The lists should now be editable, but there’s one thing left to do – show that the selected list is “active”.

Selecting Lists

Open app/js/views/lists/menuitem.js and change open to track the active menu view, and add a class name to the view’s element:

open: function() {
  if (bTask.views.activeListMenuItem) {
    bTask.views.activeListMenuItem.$el.removeClass('active');
  }

  bTask.models.activeList = this.model;
  bTask.views.activeListMenuItem = this;
  this.$el.addClass('active');

  return false;
}

Whenever a view is opened, bTask.views.activeListMenuItem will be used to store a reference to it. Notice how I’ve used this.$el? Most experienced Backbone developers will tell you to do this, rather than using jQuery’s $() to find elements based on a selector. The idea is to use minimal jQuery and be more declarative with Backbone.

Does keeping a reference to bTask.views.activeListMenuItem beat $('.list-menu-item').removeClass('active')? It’s hard to say – I’ve often noticed people dipping into jQuery where it makes sense.

This begs the question: should we really track the active list using a reference to a model? The ListMenuItemView already contains a reference to the model, and most of the Backbone code is really concerned with modeling the user interface, rather than an additional internal state. Let’s try removing the reference to bTask.models.

Open app/js/app.js and remove the models object, and then remove the line that sets activeList. Next, go to app/js/views/lists/menuitem.js and change the open method to only refer to views:

open: function() {
  if (bTask.views.activeListMenuItem) {
    bTask.views.activeListMenuItem.$el.removeClass('active');
  }

  bTask.views.activeListMenuItem = this;
  this.$el.addClass('active');

  return false;
}

Next open the AppView class, in app/js/views/app.js, and make sure editList uses bTask.views.activeListMenuItem.model. Finally, make app/js/views/lists/menu.js activate the default item (the first list):

renderMenuItem: function(model) {
  var item = new ListMenuItemView({ model: model });
  this.$el.append(item.render().el);

  if (!bTask.views.activeListMenuItem) {
    bTask.views.activeListMenuItem = item;
  }
  
  if (model.get('id') === bTask.views.activeListMenuItem.model.get('id')) {
    item.open();
  }
},

I feel like avoiding tracking an internal application state is a mistake in Backbone, and instead the views should be made to work harder. Is this a good idea? It probably depends on the nature of the application.

To make the interface clearer, you can add li.active { font-weight: bold } to app/css/app.css.

Summary

In this part we’ve built on the code in Part 6 to allow lists to be edited. Even though this is fairly simple, the application had to change to track the currently active list.

The general rule of thumb in Backbone is to use cached jQuery (or Zepto) objects, which is why you’ll see a lot of calls to this.$el rather than $(). I suggest another rule that complements this: make views do the work, and avoid relying on state external to views.

The full source for this tutorial can be found in alexyoung / dailyjs-backbone-tutorial, commit 0953c5d.

Node Roundup: AsyncMachine, require-directory, sayeasy

09 Jan 2013 | By Alex Young | Comments | Tags node modules audio express async
You can send in your Node projects for review through our contact form or @dailyjs.

AsyncMachine

AsyncMachine (License: MIT, npm: asyncmachine) by Tobiasz Cudnik is a state machine for declaring asynchronous logic. It’s written in TypeScript, and supports state definition using an object-oriented API.

Transitions between states are exposed using an EventEmitter, and promises are supported for “deferred state changes”. Although the project is written with TypeScript, the documentation includes a plain JavaScript example.

AsyncMachine isn’t based on a formalised state machine design, but it has an interesting blend of concepts from other finite state machine implementations, asynchronous programming in Node, and object-oriented design. It’s definitely got a lot of ideas on how to deal with state in an asynchronous environment.

require-directory

require-directory (License: MIT, npm: require-directory) by Troy Goode allows directories to be loaded with require as if an index.js file had been used.

If you’ve got a project with an index.js file – let’s say it’s in routes/, and it looks like this:

module.exports = {
  auth: require('./auth')
, products: require('./products')
, categories: require('./categories')
};

When it’s loaded using require('./routes'), you’ll get an object with auth, products, and categories. Troy argues that this can cause maintenance problems, and prefers to write the index.js file like this: module.exports = require('require-directory')(module);.

Files can also be blacklisted and whitelisted, and index.js will be automatically ignored.

sayeasy

sayeasy (License: MIT, npm: sayeasy) by Clay Smith is a RESTful wrapper around Mac OS X’s say command, created with Express. The author is using it to speak notifications in a continuous integration environment – you could have a sayeasy server in your office that speaks when tests start to fail.

It also has a command-line wrapper, allowing messages to be sent to a central sayeasy server.

jQuery Roundup: ParamQuery Grid, Backbone.ViewDSL, Events Demo

08 Jan 2013 | By Alex Young | Comments | Tags jquery plugins backbone.js
Note: You can send your plugins and articles in for review through our contact form or @dailyjs.

ParamQuery Grid

ParamQuery

ParamQuery Grid (GitHub: paramquery / grid, License: MIT) by Paramvir Dhindsa is a table grid plugin that’s based on jQuery UI widgets. It supports sorting, row and cell selection, built-in and custom editing, resizing, and pagination.

The author has written full API documentation for ParamQuery, and an introductory tutorial. Additional data formats can be supported with the dataModel API, but it works with XML and JSON out of the box.

Backbone.ViewDSL

Backbone.ViewDSL (GitHub: andreypopp / backbone.viewdsl, License: BSD3) by Andrey Popp is a DSL for defining Backbone.View hierarchies. Views can be automatically loaded (AMD is supported), instantiated, and interpolated.

The author’s example compares a ViewDSL class with a standard Backbone class:

class App extends Backbone.ViewDSL.View
  template: """
    <h1></h1>
    <view name="app.views.Sidebar" id="sidebar" />
    <view name="app.views.Content" id="content" />
    <div class="footer"> by </div>
    """

In that example, app.views.Sidebar refers to another Backbone.View. A view attribute is also supported, and views can be accessed with Backbone.ViewDSL.View.from. Although Andrey describes the library as ‘tiny’, it packs in other features including conditional DOM removal, and there are some PhantomJS-powered Mocha tests as well.

Events Demo

Events Demo (GitHub: liouh / js-events-demo) by Henry Liou is an interactive demo that shows how each property works on the event object jQuery passes to .on. It uses nested elements so you can see how target and relatedTarget change depending on which element the event was triggered on.

Given how many people confuse the target properties, it made me wonder if this would be better than the official jQuery documentation. This project was sent in by Anthony Ettinger.

OOGL, Jot, Conference

07 Jan 2013 | By Alex Young | Comments | Tags webgl text editor

OOGL

oogle.js

OOGL (GitHub: 71104 / oogl.js, License: MIT) by Alberto La Rocca is a thin object-oriented library to make WebGL easier to work with. It has asynchronous shader loading, texture and attribute array management, and a render loop implemented with requestAnimationFrame and a setInterval fallback.

The author has written an API reference for oogl.js, and there are some oogle.js demos as well.

Jot

Jot

Jot (GitHub: boutell / jot, License: MIT, npm: node-jot) by Tom Boutell is a text editor built with Express and some client-side libraries like Rangy, and has some options for MongoDB as well.

Media files like photos and videos are supported, using a widgets system:

Jot introduces “widgets,” separate editors for rich media items like photos, videos, pullquotes and code samples. Jot’s widgets handle these items much better than a rich text editor on its own.

Also, Jot can be configured to send uploaded files to Amazon S3 or a custom backend solution. It uses ImageMagick to process image files.

It has the usual rich text editing features as well, and supports major browsers from IE7 up.

The author has provided instructions on how to integrate Jot with another Express application.

Conference

Conference (GitHub: axemclion / conference, License: MIT/GPL) by Parashuram Narasimhan is a Backbone.js application that provides an example schedule for a conference. Designed to alleviate the symptoms of bad conference wi-fi, Conference stores the data about the conference locally to avoid requiring a data connection once it has been initially loaded.

I’ve seen conferences that use custom native mobile apps to do a similar thing, but this version would be suitable for a mobile browser as well (and free as it’s released under a permissive license). Anyway, it’s an interesting use of Backbone.js, and Parashuram would like to help conferences adopt it.