2012-06-21

Form Data Extraction with Backbone.js, Underscore.js and jQuery

Our weapon of choice for building single-page web applications is Backbone.js. Unlike a few of its competitors, such as Ember.js, Knockout, Backbone does not support model binding out of the box. There are a some libraries that add model binding support to Backbone, probably first on the block was Backbone.ModelBinding which has now been discontinued, Backbone.ModelBinder and Backbone Bindings.

Even though these libraries make sense in some cases, we have noticed that usually when starting out, Backbone's default tools (Backbone itself, Underscore.js and jQuery) are enough to get the ball rolling, as demonstrated below.

HTML

<form>
  Name: <input type="text" name="name"/>
  Age: <input type="text" name="age"/>
  <input type="submit" value="Submit"></input>
</form>

JavaScript

var UserForm = Backbone.View.extend({
  events: {'submit': 'save'},

  initialize: function() {
    _.bindAll(this, 'save');
  },
  
  save: function() {
    var arr = this.$el.serializeArray();
    var data = _(arr).reduce(function(acc, field) {
      acc[field.name] = field.value;
      return acc;
    }, {});
    this.model.save(data);
    return false;
  }
});

var userForm = new UserForm({el: this.$('form'), model: new User()});

To understand the actual data extraction I will explain serializeArray and reduce.

serializeArray is a jQuery method that takes a form and constructs an array of all the input elements that have a name attribute. The resulting array is in the following form:

[{name: "name", value: "John Smith"}, ...]

An array of maps is not quite something we are looking for, so we have to do another transformation.

reduce is used to build up a new value from the array with an original seed value (empty map) and a function. The function's first argument acc is the return value of the previous function call and the second argument field is the current element in the array. Now we have something that can be passed to Backbone.Model.save:

{name: "John Smith", age: 34}

4 comments:

  1. Hello All,

    Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface. Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js. But without extending any of the built-in JavaScript objects. It's the tie to go along with jQuery's tux, and Backbone.js's suspenders. A key activity in web automation is the extraction of data from websites, also known as web scraping or screen scraping. Thank you...

    ReplyDelete
  2. This is very elegant! Thanks!

    ReplyDelete