Build a Contacts Manager Using Backbone.js: Part 5

Build a Contacts Manager Using Backbone.js: Part 5

Tutorial Details
  • Applications Used: Backbone.js, jQuery
  • Difficulty: Intermediate
  • Completion Time: 30 Minutes
This entry is part 5 of 5 in the Getting to Know Backbone.js Session
« Previous

Welcome back to the Building a content viewer with Backbone series. Over the first four parts, we looked at almost every major component that ships with the latest version of Backbone including models, controllers, views and routers.

In this part of the tutorial, we’re going to hook our application up to a web server so that we can store our contacts in a database. We won’t be looking at LocalStorage; this is a popular means of persisting the data that Backbone apps use, but the fact is there are already a number of excellent tutorials available on this subject.


Getting Started

We’ll need a webserver and a database for this part of the tutorial. I use Microsoft’s VWD as an editor, which ships with a built-in web server and works well with MSSQL server, so this is what we’ll be using. In truth, it doesn’t really matter which stack you decide to go with.

Installing and configuring either of these technologies (VWD and MSSQL server) is beyond the scope of this tutorial, but it’s relatively straight-forward to do and there are plenty of good guides out there.

Once installed, you’ll want to set up a new database containing a table to store the data in. The table columns should mirror the different properties our models use, so there should be a name column, an address column, etc. The table can be populated with the example data we’ve used throughout the series so far.

One column that should appear in our new table, but which we haven’t used in our local test data is an id, which should be unique to each row in the table. For ease of use, you probably want to set this to auto-increment when the data is added to the table.


Backbone Sync

In order to communicate with the server, Backbone gives us the Sync module; this is the only major module that we haven’t used yet and so understanding it will complete our knowledge of the fundamentals of the framework.

Calling the sync() method results in a request being made to the server; by default, it assumes either jQuery or Zepto is in use and delegates the request to whichever of them is present to actually perform. It also assumes a RESTful interface is awaiting on the back-end so by default makes use of POST, PUT, GET, DELETE HTTP methods. As we’ve seen, Backbone can be configured to fall back to old-school GET and POST methods with additional headers which specify the intended action.

As well as being able to call sync() directly, models and collections also have methods that can be used to communicate with the server; models have the destroy(), fetch(), parse() and save() methods, and collections have fetch() and parse(). The destroy() fetch() and sync() methods all defer to sync() whether being used with models or collections. The parse() method, called automatically whenever data is returned by the server, is by default a simple no-op which just returns the response from the server, but can be overridden if we wish to pre-process the response before consuming it.


Page Load Caveat

The way model data is bootstrapped into the page will vary depending on the back-end technology being used.

The Backbone documentation for the fetch() method (of a collection) states that this method should not be used on the initial page load to request the required models from the server. It goes on to elaborate in the FAQ section that a page should have the required modules already available to the page on load to avoid the initial AJAX request.

This is a great idea and while we don’t explicitly have to follow the advice, doing so will make our application just a little bit snappier, and that can only be a good thing.

The way model data is bootstrapped into the page will vary depending on the back-end technology being used. We’re going to be using .net in this example, so one way of doing this would be to dynamically create a <script> element containing the required model data, and inject it into the page. To do this we’ll need to convert our index.html file to index.aspx instead (we’ll also need an index.aspx.cs code-behind or class file too). But doing this raises a new issue.


Using Underscore Microtemplates in an ASPX Page

We can lift the ‘Mustache-style’ example straight off of the Underscore documentation page.

The problem with Underscore templates is that they use <%= to specify placeholders in the template that are replaced with actual data when the template is consumed. This is the same syntax that ASPX pages use to run dynamic .Net code within HTML tags. The Underscore templates that we’ve used in this example so far prevent the ASPX page from running correctly and instead it displays a server error.

Fortunately there are several ways around this problem, the simplest way being to change the syntax used to specify the placeholders used in the templates. Underscore exposes the templateSettings property for this very purpose, allowing us to easy specify a regular expression used to match the symbols we wish to use. We can lift the ‘Mustache-style’ example straight off of the Underscore documentation page in fact; at the start of our app.js file (within the very outer function) we can just add the following code:

_.templateSettings = {
    interpolate: /\{\{(.+?)\}\}/g
};

All this does is supply a new regular expression to the interpolate method, which allows us to use the alternative syntax {{ property }} instead of <%= property %>. We should also at this point go through the templates and change all of the original template tags to use the new syntax.

Although this is not something we’ve used in our templates so far, there are also additional symbols that Underscore can use. We can evaluate JavaScript using <% and can escape data using <%-. If we wish to use these in our templates and have replaced the interpolate property, we should also configure the evaluate and escape Underscore properties as well.


Bootstrapping the Model Data

We can now think about delivering the model data that is stored in a database to our page when the page is initially rendered. We can easily do this be adding a simple method to the class file for our ASPX page that reads the records from the database and creates a list of objects where each object represents a single contact. We can then serialise the list into a JavaScript array and inject it into the page. As long as the array has the same format as the dummy array we used in the first four parts of this tutorial, we won’t have to change our front-end code.

As a placeholder for the array, we can just add a new <script> element to the body of the page, directly before the reference to app.js, which calls the method in the code-behind:

<script>
    var contacts = <%= getData() %>
</script>

The actual logic in the code-behind that performs the database read and list serialisation could vary wildly depending on the implementation, and is somewhat beyond the scope of this tutorial – we’re more interested in getting that initial payload on the page than we are about how we actually get it. Feel free to check out the class file in the accompanying code download for probably the quickest and easiest, but by no means the best, way to do it.

At this point, we should be able to remove the contacts array that held our dummy data from app.js, run the page (through the built-in WVD webserver, or IIS) and see exactly the same page, with almost the same functionality, as we saw at the end of part 4. Yay!


Syncing Our App With the Server

In this example, I’ve used a .net 4.0 ASMX file to handle the requests from the front-end. In order for the back-end to see the data sent to it, we should configure the emulateHTTP and emulateJSON Backbone properties. Add the following lines of code directly after where we changed Underscore’s template syntax:

Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;

Whether or not you’ll need to configure these properties when building a Backbone app for real depends entirely on the back-end technology you choose to work with.

So, our application could modify the data in several ways; it could change the attributes of a contact that already exists, it could add an entirely new contact, or it could delete a contact that already exists.

The logic to do all of these things on the front-end already exists, but now that a server is involved, the behaviour of the page has already changed. Although the page will render as it did before, if we try to delete a contact, Backbone will throw an error complaining that a url has not been defined. The reason for this is because we used the destroy() method in the deleteContact() method of our ContactView class.

Let’s look at how to restore the delete functionality. The first thing we should do then is define a url attribute for our models. Add the property to the Contact class that defines an individual model:

url: function () {
    return "/ContactManager.asmx/ManageContact?id=" + this.get("id");
}

We specify a function as the value of the url property, which returns the URL that should be used to make the requests to. In this example, we can use an asmx web service file to handle the requests. We also add the name of our web method (ManageContact) and add the id of the model as a query string parameter.

Now if we delete one of the contacts when we run the page a POST request is made to the web service. An X-HTTP-Method-Override header is added to the request which specifies that the intended HTTP method was DELETE. We can use this in our web service logic to determine what action to take on the database.

Next we can update the saveEdits() method of the ContactView class so that it notifies the web service when a contact is edited; change the line of code that uses the set() method so that it appears like this:

this.model.set(formData).save();

All we do is chain the save() method on to the set() method. The save() method delegates to the sync() method which makes a POST request to the server. As before the id of the model is sent as a query string and an X-HTTP-Method-Override is used to specify the intended PUT method. This time however, the Content-Type header is set to application/x-www-form-urlencoded (if we didn’t configure the emulateJSON property it would be application/json) and the model data is sent as a form data, which we can use to make whatever changes are necessary.

All that is left to do on the front-end is to update the addContact() method of the DirectoryView class. Previously in this method we had an if statement that checked the type of the model being added to see if the select menu needed to be updated. We should now change that if statement so that it appears as follows:

if (_.indexOf(this.getTypes(), formData.type) === -1) {
    this.$el.find("#filter").find("select").remove().end().append(this.createSelect());
}

this.collection.create(formData);

We’ve trimmed the if statement down to remove the else condition, making the code a bit tidier. We’ve also removed the add() method and added the create() method in its place. The create() method will actually add the new model to the collection automatically without us manually creating a new instance of our model’s class, and it will also make a request to the server, once again delegating to sync().

This time the X-HTTP-Method-Override header does not need to be set, because POST is the method that we would use were the request being made to a RESTful interface anyway. As with the save() method, the model data passed to the create() method is delivered to the server as form data.

As with the server-side code used at the start of this part of the tutorial to bootstrap the initial model data into our app, the code used to process and handle the requests made by Backbone is beyond the scope of the tutorial. We’re interested only in the front-end here. As before, the Web service used for this demo is included in the code archive and is fully commented, so check it out if you’re interested. I’ve also included a database backup, which you should be able to restore in order to get going with the demo data.


Summary

In this part of the tutorial, we looked at some of the methods we can use which delegate to Backbone’s sync() method in order to communicate with a back-end that can persist the changes made using the front-end of the application.

We saw how Backbone by default makes RESTful requests to a specified URL and how we can configure it in order to work with legacy servers that do not operate on REST principles. We also looked at some of the methods that delegate to sync() in order to communicate with the server. Specifically, we covered the remove(), save() and create() methods and looked at what is sent to the server and how.

We also looked at how easy it is to change the symbols that Underscore uses in order to interpolate data into a template. This now concludes the Contact Manager tutorial; while there are many more features we could add to the application, we have now covered the basics of what it takes to build a fully-functional application using the excellent Backbone.js. Thanks for reading.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://website-tuts.blogspot.com dan

    A demo would be good and when I clicked download the source files it took me here:
    http://nettuts.s3.amazonaws.com/1150_bb5/demo.zip

  • wes

    Another good one, keep it up!

  • Rafael

    For me, this is one of the best parts of backbone…Also, backbone offers some good events for models and collections to deal with this server side methods, like add, reset, change and a few others. i love it

  • Fritz

    Hey guys,
    nice tutorial. May you solve this error for the demo:

    This XML file does not appear to have any style information associated with it. The document tree is shown below.

    Thanks!

  • Max

    Could you please fix the demo link?

  • Amit Erandole

    Hey Dan,

    I really wish you could show us how to do this last part with straight PHP and MySql

    • pinksy

      +1

  • http://www.rcdmk.com RCDMK

    I’ve built an ASP.Net and an ASP.Net MVC 3 solution (not so easy to grasp and overcome all of the points, but worked).

    Here is the link for the MVC 3 project: http://www.4shared.com/zip/Tvmubgsm/backboneContacts.html

    • http://philkershaw.me Phil

      @RCDMK: Any chance you could put this up on GitHub or BitBucket?

      @Dan Wellman: This is a nice series, thank you. Is there any chance of having the downloadable source converted to PHP and/or NodeJS? The tutorial is easy enough to follow for any language but if there was a code example for the full project in these 2 languages that would be most helpful.

  • http://www.marcoleong.com Marco

    The download source file link for this tuts is dead. Does anyone have a mirror? Or the author can fix it?

  • http://www.lincore.com honestjoe

    Some of my post is missing – I will zip and post my workings asap. you can find me by searching jbennie or lincoreltd

  • Novack

    Fix the damn link already!

  • Wilson Keenan

    I’m looking to persist data in a database, so I had a few questions.

    I’d like to hook up with MongoDB – because they have a REST API. Can you please explain if it’s possible to connect directly to mongo via simple ajax calls or do I have to implement node.js / socket.io.

    I want to keep this simple (given that I’m just trying to complete the tutorial and learn more about backbone). I’m new to Mongo (just done MySQL in the past..), but it seems like its set up perfectly to handle this task w/out much help or extra work.

    • Henry

      For internal app / test/demo app, maybe.

      But usually DB, even with RESTful API, should be hidden behind the Application layer for security / access control reason.

    • http://vincentmac.com Vincent

      If you are using node on the server side, you should be able to use Mongoose (mongoosejs.com) to connect to MongoDB. I’ll look into updating my github project (github.com/vincentmac/ContactManager) for this tutorial to use mongo.

  • Colly

    One of the more easy to follow backbone demos – thanks!

    SQL Code for the db table to speed things up a bit (MySQL DB)

    CREATE TABLE `backbone`.`testtable` (
    `id` INT NOT NULL AUTO_INCREMENT ,
    `name` VARCHAR( 50 ) NOT NULL ,
    `address` VARCHAR( 100 ) NOT NULL ,
    `tel` VARCHAR( 15 ) NOT NULL ,
    `email` VARCHAR( 50 ) NOT NULL ,
    `type` VARCHAR( 20 ) NOT NULL ,
    PRIMARY KEY ( `id` )
    )

  • Kalpesh

    I want same example for PHP.
    is it possible?

  • http://www.perisicdesigns.com Stevo

    Ok, I’ve been wrestling with backbone and straight PHP for a few days, and this is what I learned, I hope it helps folks here trying to understand how backbone communicates with PHP.

    In order to receive the JSON information sent by backbone you first have to look into the $_SERVER global and get the REQUEST_METHOD, than perform a switch() {case:} to match the request and the action like this:

    If anyone else has more to add or some better explanation I would love to hear it.

    Thanks for the great Tut!

    Stevo

    • http://www.perisicdesigns.com Stevo

      for some reason the code did not make it in the comment, so here it is again:

      <?php
      $requestMethod = $_SERVER["REQUEST_METHOD"];

      switch ($requestMethod) {
      case ‘POST’:
      $data = json_decode(file_get_contents(‘php://input’), true);
      mysql_query(“INSERT INTO your_table (your_column) VALUES (‘”.$data["key"].”‘)”);
      break;
      }
      ?>

  • Thomas O’Rourke

    Great tutorial, thanks!

    I totally understand that the server part is to show how to connect it up… Not really the point of the tutorial… – I’m not a big fan of that .Net code :)

    I’m more of a server guy trying to learn backbone, so making the server is the easy part :)

    For some of the other readers who want a simple server: Sinatra + Mongo

    I would use Sinatra for the server part. It’s dead simple, is perfect for simple REST APIS, and you can easily produce JSON and connect it up to MongoDb, or Mysql, whatever. Using the vanilla Mongo Ruby driver is only a few lines of code. With Sinatra would also get nice things like the parameter parsing, headers, JSON out, (actually if you use Mongo, you can pretty much pass JSON straight through).. etc.. If I get a chance I will post the server code…

    • rowild

      I’ll get you on your last sentence… any chance for the code? Thanks!

  • Fred

    LOL you used a meme. Well funny. You’re a propa codur.

  • Matt

    So far this isn’t working for me. When I click to delete a contact, the same things happen as previous: the article is removed from the page, and the item is deleted from the contacts array. No POST request is sent from the browser. You write, “now that a server is involved…” — but how does my app know that a server is involved now? All I’ve done in my JS, other than establishing the array of contacts through a select on the database table, is to set values for Backbone.emulateHTTP and Backbone.emulateJSON. Thanks.

    • Matt

      Nobody out there? Syncing with the server is the part I’m most interested in, so any help would be appreciated – thanks.

      • Matt

        Guess I’ll look elsewhere for backbone.js tutorials.

  • Ian

    Thanks for the aspx info. I’m only on part 3 of this series but found this page while looking for a fix. I actually disable asp on my server but usually use a virtualhost. This time I just dropped the folder in my sandbox and used localhost and it messes up with .html page too because by default the asp engine is trying to parse everything if you don’t disable it per site.

    In other words if someone wants they can disable asp on a per site basis and keep the original underscore syntax.

    I don’t remember at the moment what I did to disable it but I did because my virtual sites have no problem with underscore syntax.

  • http://twitter.com/Seanmyr Sean Meyer

    In general this has been a good tutorial, at least up until now. I personally know absolutely nothing about .Net or aspx or whatever and I don’t want to learn it. I do have PHP experience but I have to admit that I’m at a complete loss as to how to do this last part of the tutorial with PHP. Could someone please direct me to a tutorial on this? Or would it be better to just learn node.js and mongodb or whatever and then come back to this last part of this tutorial?

  • SPeed_FANat1c

    I am trying to do it on php, but I had to move scruipt tags upper to the head tag. Because for some unknown reason they are not rendered. And then I get error:

    GET http://localhost/backbone_contacts_manager/%3C%=%20photo%20%%3E 400 (Bad Request)

    This has something to do with render() methods, when I cooment them out the error dissapppears. But I don’t know what else to do.

  • SPeed_FANat1c

    found out where the error came from:

    _.templateSettings = {

    // interpolate: /{{(.+?)}}/g // {{ }} syntax for templating insteat of of

    };

    even when this was commeted out, template did not recognize the tags. So I had to comment out all _.templatesettings and then it used default regex for recognizing tags.

  • SPeed_FANat1c

    addContact function is throwing error:

    Uncaught ReferenceError: formData is not defined

    And I checked demo files – its changed to formData, but in our code it was newModel object.