Adrian Mejia's [code]Blog

var life = { "work_hard","have_fun","make_history" };

Backbone.js for Absolute Beginners - Getting Started (Part 4: Routers)

| Comments

The part 3 of this tutorial is here.

2.6 Backbone.Router

You could build web application without using the routers. However, if you want to make reference to certain ‘state’ or location of the web application, you need a reference (link/URL) to it. This is where routers come to rescue.

Routing in most of JS application are achieved by hash-tags. E.g. If you take a look of Gmail URL you will see something like:

https://mail.google.com/mail/u/0/#inbox/139c0d48e11d986b

where the #inbox/139c0d48e11d986b is the hash-tag which reference some email location.

In backbone, routes are hash maps that match URL patterns to functions. You can use parameter parts, such as todos/:id, or using splats file/*path you will match all the parameters from the splat on. For that reason, the splat parameter should be always the last matcher.

2.6.1 Initializing the Router

In our Todo app, we are going to use routers to filter between the tasks that are pending and the ones that have been completed. So, let’s initialize the routes this way:

Define Router Full Code
1
2
3
4
5
6
7
8
9
10
    app.Router = Backbone.Router.extend({
      routes: {
        '*filter' : 'setFilter'
      },
      setFilter: function(params) {
        console.log('app.router.params = ' + params); // just for didactical purposes.
        window.filter = params.trim() || '';
        app.todoList.trigger('reset');
      }
    });

Now, you need to initialize it, adding this lines:

Initialize router Full Code
1
2
3
4
5
6
7
     //--------------
     // Initializers
     //--------------

+    app.router = new app.Router();
+    Backbone.history.start();    
     app.appView = new app.AppView();

You can test that you router is working just typing #anything/that/you/want and seeing the parameter in you browser’s console.

2.6.1 Processing the routes

Before rendering the list of items, you need to check the parameters to wether show only the pending ones, or the completed or show them all. As shown in the code snipet below.

Processing the routes in app.AppView Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@@ -164,7 +177,18 @@
       },
       addAll: function(){
         this.$('#todo-list').html(''); // clean the todo list
-        app.todoList.each(this.addOne, this);
+        // filter todo item list
+        switch(window.filter){
+          case 'pending':
+            _.each(app.todoList.remaining(), this.addOne);
+            break;
+          case 'completed':
+            _.each(app.todoList.completed(), this.addOne);
+            break;            
+          default:
+            app.todoList.each(this.addOne, this);
+            break;
+        }
       },
       newAttributes: function(){
         return {

If you try adding the words #/pending or #/completed at the end of the URL you’ll get an error!. That’s a good sign, it means the routes are working, but we haven’t implemented the app.todoList.remaining() and app.todoList.completed(). So, that’s next:

Defining ‘completed’ and ‘remaining’ functions in app.TodoList Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@@ -85,7 +90,15 @@
     //--------------
     app.TodoList = Backbone.Collection.extend({
       model: app.Todo,
-      localStorage: new Store("backbone-todo")
+      localStorage: new Store("backbone-todo"),
+      completed: function() {
+        return this.filter(function( todo ) {
+          return todo.get('completed');
+        });
+      },
+      remaining: function() {
+        return this.without.apply( this, this.completed() );
+      }      
     });

Now, if you try again adding the hash-tags it will work! But, it will be better if the user can have links to that instead of typing URLs. So, let’s add them.

Show routes’ links Full Code
1
2
3
4
5
6
7
8
9
10
11
12
@@ -32,6 +32,11 @@
     <header id="header">
       <h1>Todos</h1>
       <input id="new-todo" placeholder="What needs to be done?" autofocus>
+      <div>
+        <a href="#/">show all</a> |
+        <a href="#/pending">show pending</a> |
+        <a href="#/completed">show completed</a>
+      </div>      
     </header>
     <section id="main">
       <ul id="todo-list"></ul>

Well, that’s all! If completed these 4 parts tutorial you will be familiar with the main Backbone modules (Models, Collections, Views, Events, and Routes). To increase you knowledge you can follow the following resources:

Hope it was helpful!

Backbone.js for Absolute Beginners - Getting Started (Part 3: CRUD)

| Comments

The part 2 of this tutorial is here.

2.5 Todo item list CRUD

There are a couple of features that we could improve. Let’s implement the CRUD (Create-Read-Update-Delete) for the item list.

2.5.1. C-reate

We are already can create item list from the console (2.3) and also from the UI (2.4.3). So, it’s done.

2.5.2. U-pdate

What if you make a mistake and want to change the text on some of your to-do list. Furthermore, you can notice that the checkboxes states are not persistent when you reload the pages. Let’s fix both problems.

1.- You want to respond to a double click event showing up a text box, where the user can change the text. First, let’s add the HTML in the item-template template below the label tag.

<input class="edit" value="<%- title %>">

2.- If you refresh, you will notice that there are both displaying at the same time. So, you can hide them properly with the following CSS.

CSS Full Code
1
2
3
4
5
6
7
8
9
10
    #todo-list input.edit {
      display: none; /* Hides input box*/
    }
    #todo-list .editing label {
      display: none; /* Hides label text when .editing*/
    }
    #todo-list .editing input.edit {
      display: inline; /* Shows input text box when .editing*/
    }

3.- Then, we need to add the events to the TodoView class to respond to the changes.

Todo Model Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    // renders individual todo items list (li)
    app.TodoView = Backbone.View.extend({
      tagName: 'li',
      template: _.template($('#item-template').html()),
      render: function(){
        this.$el.html(this.template(this.model.toJSON()));
        this.input = this.$('.edit');
        return this; // enable chained calls
      },
      initialize: function(){
        this.model.on('change', this.render, this);
      },
      events: {
        'dblclick label' : 'edit',
        'keypress .edit' : 'updateOnEnter',
        'blur .edit' : 'close'
      },
      edit: function(){
        this.$el.addClass('editing');
        this.input.focus();
      },
      close: function(){
        var value = this.input.val().trim();
        if(value) {
          this.model.save({title: value});
        }
        this.$el.removeClass('editing');
      },
      updateOnEnter: function(e){
        if(e.which == 13){
          this.close();
        }
       }
    });

You can find the diff that were added to implement the update feature.

Here are the changes to fix the update for the checkboxes.

2.5.2. D-elete

To be able to remove to-do items, we need to add a remove button in each item and listen to the click event on it, which will trigger the destroy function in the selected todo object.

1.- Add the HTML markup for the remove button.

Remove Button into ‘item template’ Full Code
1
2
3
4
5
6
7
@@ -47,6 +47,7 @@
       <input class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>>
       <label><%- title %></label>
       <input class="edit" value="<%- title %>">
+      <button class="destroy">remove</button>
     </div>
   </script>

2.- Listen for the click event in the button that you just created.

Add event listeners for the Remove Button in ‘app.TodoView’ Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@@ -105,12 +106,14 @@
       },
       initialize: function(){
         this.model.on('change', this.render, this);
+        this.model.on('destroy', this.remove, this); // remove: Convenience Backbone'
       },
       events: {
         'dblclick label' : 'edit',
         'keypress .edit' : 'updateOnEnter',
         'blur .edit' : 'close',
-        'click .toggle': 'toggleCompleted'
+        'click .toggle': 'toggleCompleted',
+        'click .destroy': 'destroy'
       },
       edit: function(){
         this.$el.addClass('editing');

3.- Add the destroy method to the TodoView.

Add the destroy method to ‘app.TodoView’ Full Code
1
2
3
4
5
6
7
8
9
10
@@ -130,7 +133,10 @@
       },
       toggleCompleted: function(){
         this.model.toggle();
-      }
+      },
+      destroy: function(){
+        this.model.destroy();
+      }      
     });

You can download the full working code so far in here and you can visualize the changes needed to implement the delete feature in here

Continue with the 4th part and learn about Backbone’s Routes!

Backbone.js for Absolute Beginners - Getting Started (Part 2: Models, Collections and Views)

| Comments

The part 1 of this tutorial is here

2. Todo App in Backbone (Models, Collections, View and Events)

After completing this example app, you will have experience and basic understanding of all the modules of Backbone!

(Revised: 2013-02-02)

2.1.- Todo app Boiler plate

Let’s start again with the initial HTML file used on 1.1. Now, instead of div#container let’s add the following HTML code:

HTML Structure Full Code
1
2
3
4
5
6
7
8
9
10
  <section id="todoapp">
    <header id="header">
      <h1>Todos</h1>
      <input id="new-todo" placeholder="What needs to be done?">
    </header>
    <section id="main">
      <ul id="todo-list"></ul>
    </section>
  </section>

We are going to implement a To-do list, which is basically un-ordered list (ul) of elements with checkboxes.

2.2.- Backbone.Model

Models are the heart of every application. It contains the interactive data and the logic surrounding it, such as data validation, getters and setters, default values, data initialization, conversions and so on. For our example, we are going to create a model called Todo, which will store a string of text (title) and whether the task has been completed or not.

Todo Model Full Code
1
2
3
4
5
6
7
8
    var app = {}; // create namespace for our app

    app.Todo = Backbone.Model.extend({
      defaults: {
        title: '',
        completed: false
      }
    });

Notice, that for convention classes names are capitalize, while instance variables and objects are not. Another important aspect of models it’s that their properties are dynamic; they can be created on the fly and doesn’t have any specific type associated.

Test what you just coded!

After you completed the code snippet above you can open your browser console (chrome’s console: ctrl+shift+i -or- ⌘+alt+i) and try this out, to get familiar with the models:

Practice in your Browser's console
1
2
3
4
5
6
var todo = new app.Todo({title: 'Learn Backbone.js', completed: false}); // create object with the attributes specified.
todo.get('title'); // "Learn Backbone.js" 
todo.get('completed'); // false
todo.get('created_at'); // undefined
todo.set('created_at', Date());
todo.get('created_at'); // "Wed Sep 12 2012 12:51:17 GMT-0400 (EDT)"

2.3.- Backbone.Collection

As its name indicates, collections are ordered sets of models, where you can get and set models in the collection, listen for events when any element in the collection changes, and fetching for model’s data from the server.

Collections allows to save data (in database, file, memory), and it requires a reference to it. Therefore, you need to specify the url parameter with a relative url, where the model’s resource would be located on the server. Otherwise, you will get errors like:

A "url" property or function must be specified

We are not going to use a backend server for simplicity (I will do a new post for that); instead we are going to use HTML5’s local storage for persistence through a Backbone’s plugin. So, we need to define the localStorage property instead of URL.

Todo list Collection Full Code
1
2
3
4
5
6
7
    app.TodoList = Backbone.Collection.extend({
      model: app.Todo,
      localStorage: new Store("backbone-todo")
    });

    // instance of the Collection
    app.todoList = new app.TodoList();

Test what you just your coded!

(Google’s Chrome console shortcuts: ctrl+shift+i -or- ⌘+alt+i)

Practice in your Browser's console
1
2
3
4
5
6
var todoList = new app.TodoList()
todoList.create({title: 'Learn Backbone\'s Collection'}); // notice: that `completed` will be set to false by default.
var lmodel = new app.Todo({title: 'Learn Models', completed: true});
todoList.add(lmodel); // ["Learn Backbone's Collection", "Learn Models"]
todoList.pluck('title'); // [false, true]
JSON.stringify(todoList); // "[{"title":"Learn Backbone's Collection","completed":false,"id":"d9763e99-2267-75f5-62c3-9d7e40742aa6"},{"title":"Learn Models","completed":true}]"

2.4.- Backbone.View

As mentioned in 1.2, Views doesn’t have the HTML markups for our application, but instead (It’s like the controller in MVC frameworks) process data and link it to templates and it finally render HTML based on events or data changes.

2.4.1.- Basic Properties

There are 4 basic properties in a view: el, initialize, render, and events.

We have already seen the first 3 and will see later the fourth one. Do you remember the Hello World View from 1.2?

Example of a Backbone.View
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    var AppView = Backbone.View.extend({
      // el - stands for element. Every view has a element associate in with HTML 
      //      content will be rendered.
      el: '#container',
      // It's the first function called when this view it's instantiated.
      initialize: function(){
        this.render();
      },
      // $el - it's a cached jQuery object (el), in which you can use jQuery functions 
      //       to push content. Like the Hello World in this case.
      render: function(){
        this.$el.html("Hello World");
      }
    });

2.4.1.1.- view.el

Every view needs to reference a DOM at all times. Therefore, the view will inject content into this element. This is the el property. this.el is created from view’s el,tagName, className, id or attributes properties. If none of these are specified, then this.el is an empty div. The view.$el it’s a cached jQuery object of the view’s element (view.el).

2.4.1.2.- Initialize/construtor

Here you have the option to pass parameters that will be attached to a model, collection or view.el.

2.4.1.3.- render

In this function, you inject the markup into the elements. Not all views require having a render function, as you are going to see in the sample code, they can call other view’s render functions.

2.4.1.5.- delegated events

Events are written in the {"<EVENT_NAME> <ELEMENT_ID>": "<FUNCTION_CALLBACK>"} format. E.g. events: {'keypress #new-todo': 'createTodoOnEnter'}

2.4.2.- Todo View

Now back to our To-do application: We need a view that renders each of the todo model objects into the page. The item-template and app.TodoView will render each todo item.

item-template Full Code
1
2
3
4
5
6
   <script type="text/template" id="item-template">
      <div class="view">
        <input class="toggle" type="checkbox">
        <label><%- title %></label>
      </div>
    </script>
Todo View Full Code
1
2
3
4
5
6
7
8
9
    // renders individual todo items list (li)
    app.TodoView = Backbone.View.extend({
      tagName: 'li',
      template: _.template($('#item-template').html()),
      render: function(){
        this.$el.html(this.template(this.model.toJSON()));
        return this; // enable chained calls
      }
    });

2.4.3.- App View

Now, we need another view that take a collection and render each of the individual items. We are going to call it ‘AppView’. Take a look through this code and try to identify each of the elements (we have already describe them in the previous sections).

Todo View Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    // renders the full list of todo items calling TodoView for each one.
    app.AppView = Backbone.View.extend({
      el: '#todoapp',
      initialize: function () {
        this.input = this.$('#new-todo');
        app.todoList.on('add', this.addAll, this);
        app.todoList.on('reset', this.addAll, this);
        app.todoList.fetch(); // Loads list from local storage
      },
      events: {
        'keypress #new-todo': 'createTodoOnEnter'
      },
      createTodoOnEnter: function(e){
        if ( e.which !== 13 || !this.input.val().trim() ) { // ENTER_KEY = 13
          return;
        }
        app.todoList.create(this.newAttributes());
        this.input.val(''); // clean input box
      },
      addOne: function(todo){
        var view = new app.TodoView({model: todo});
        $('#todo-list').append(view.render().el);
      },
      addAll: function(){
        this.$('#todo-list').html(''); // clean the todo list
        app.todoList.each(this.addOne, this);
      },
      newAttributes: function(){
        return {
          title: this.input.val().trim(),
          completed: false
        }
      }
    });

    //--------------
    // Initializers
    //--------------   

    app.appView = new app.AppView();

Continue with the 3rd part and learn how to make CRUD for your models!

Backbone.js for Absolute Beginners - Getting Started (Part 1: Intro)

| Comments

Backbone.js is a JavaScript framework, among many others, that is gaining special attention in the web development community because it’s ease of use and the structure that it provides to JavaScript applications.

(Revised: 2013-02-02)

Brief Background (optional reading)

TL; DR: You need to use JavaScript heavily in order to make responsive and interactive web applications. Jump to this and get started.

The web application development process has been evolving over the years. In its beginning… the they were just static HTML pages, which required programmers change the code (HTML, CSS, JS) to change the content. Later, in web 2.0, server side programming languages (like PHP, Ruby, Java, …) were added to generate HTML pages dynamically based on user inputs and data stored in database. That was huge improvement, and most of the pages served today use this approach. However, to provide even more responsiveness of the website, speed and enhance the user interaction, it requiress to bring the logic closer to the client (browser). There are a couple of languages that can run in the browsers besides JS, such as Java, Flash and others. However, these ones require extra plugins and are not universally accepted as JavaScript.

Therefore, web apps nowadays require heavy use of JavaScript to generate content on the fly and quickly. The user can’t wait between request. A lot of the logic/code that used to be in the server side is being moved to the client side. JS allows the web sites to render only the parts of the website that changed and not the full-page on every request. Examples of this kind of web apps are Gmail, Pandora, Pinterest, Nokia Maps 3D and others.

A common problem with large JS web apps developed is that it became pretty messy really quick. The lacks of structure it’s hard to maintain. This is where Backbone comes into play. It provides structure to organize the code and increase maintainability. Backbone is not the only one; in fact, there are many JS frameworks that accomplish similar results like Ember.js, Angular.js and so on. However, I choose Backbone because is one of the most widely spread framework in its category. It has a vibrant community and it’s also being fully used in production for a considerable number of big companies like: Wal-Mart mobile, Groupon, Khan Academy, Pandora, Wordpress, Foursquare, and so on.

Just enough to get started with Backbone.js

Backbone.js has hard dependency on underscore.js and a soft dependency on jQuery. It’s composed by the following modules:

  • Views
  • Events
  • Models
  • Collections
  • Routers

Shut up and show me the code!

Alright! the way we are going to explore all of these modules it’s through examples. This is a practical tutorial that I wished I had it when I stared learning. So, this is a fat-free walkthrough Backbone.js, as simple as it could be, all the code is in one file just for didactical purposes (no hidden magic tricks, all cards are on the board).

The first example is a ‘Hello World’ app in Backbone and the second it’s a Todo App. After doing these 2 apps, you’ll see in action every Backbone module and have practical understanding about them.

1. Hello World in Backbone.js

You can follow alone this tutorial’s code in this repository. Each feature implemented it’s a new commit, so you can easily see what changed in every step.

1.1.- Simple HTML5 and Backbone boilerplate

To get started download this simple html file. This file contains the libraries that you’ll need (jQuery, Underscore.js, Backbone.js and Backbone-localStorage.js) and the placeholders for your HTML and JS code. Don’t worry about the libraries we are going to explain them, as we need them.

After downloading the file, notice the HTML where all your page will be built using Backbone.Views!

All your js app will be loaded here:

<div id="container">Loading...</div>

1.2.- Backbone’s Views

Backbone’s Views are the equivalent of ‘controllers’ on MVC frameworks (like Ruby on Rails), if you are not familiar with MVC frameworks nevermind. Backbone’s Views glues together user events (clicks, pressed keys …), render HTML views and templates, and interacts with models which contains the data of the application.

Here is an example of a Backbone.view: READ the code and COMMENTS, then insert this code in the javascript block in the HTML file that you downloaded.

Simple Backbone.View Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    var AppView = Backbone.View.extend({
      // el - stands for element. Every view has a element associate in with HTML 
      //      content will be rendered.
      el: '#container',
      // It's the first function called when this view it's instantiated.
      initialize: function(){
        this.render();
      },
      // $el - it's a cached jQuery object (el), in which you can use jQuery functions 
      //       to push content. Like the Hello World in this case.
      render: function(){
        this.$el.html("Hello World");
      }
    });

1.3.- Test the app

After copying the code, open the file, refresh the browser and you should see the ‘Hello World’ message… right? Wait, if you just seeing just ‘Loading…’ it’s because you need to initialize the view first.

var appView = new AppView();

Yay! you have your Hello Wold in Backbone and intro to the View module. (Full code it’s here)

1.4.- Backbone’s Templates

Backbones has a utility/helper library called underscore.js and you can use their template solution out-of-the-box, but you can use any other template solution that you want like mustage or handlerbars. Let’s stick with _.js’s template for simplicity sake.

Underscore.js template has the following signature:

_.template(templateString, [data], [settings])

where in the templateString you use the place holder <%= %> and <%- %> to substitute them with data. The later does HTML escape while the first one doesn’t. Moreover, you can use <% %> to run any javascript code.

Let’s see it in action and rewrite our Hello World using template instead.

Simple Backbone.View and Templates Full Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    var AppView = Backbone.View.extend({
      el: $('#container'),
      // template which has the placeholder 'who' to be substitute later 
      template: _.template("<h3>Hello <%= who %><h3>"),
      initialize: function(){
        this.render();
      },
      render: function(){
        // render the function using substituting the varible 'who' for 'world!'. 
        this.$el.html(this.template({who: 'world!'}));
        //***Try putting your name instead of world.
      }
    });

    var appView = new AppView();

Run the app again and verify that it’s working with the template.

Continue with the 2nd part and learn more about backbones’ Models, Collections, View and Events!

Instagram Mobile Design Secrets Revealed

| Comments

Instagram is a very nice iPhone App. It allows you to give effects to your photos easily. Additionally, it’s blazing fast to upload your photos, and share them in other social networks such as Facebook, Twitter and/or Foursquare.

This app went from 0 to 12 million users in just 12 months! And today 30+ million users in less than 2 years. Go through the slideshows bellow and you can see why. This app has some design features that that improves a lot the user experience. One of them, it’s responding to the user actions instantly even though the task is still performing in the background… more details in the slide:

Scaling Instagram has also an interesting history: