Adrian Mejia’s Blog

var life = { ‘work_hard’, ‘have_fun’, ‘make_history’ };

AngularJS Tutorial for Beginners With NodeJS ExpressJS and MongoDB

| Comments

This tutorial is meant to be as simple as possible and at the same time teach you how to connect AngularJS with backend servers in Node.js, Express.js and databases such as MongoDB, also known as the MEAN stack. Let’s start with angularJS

Brief Background (AngularJS vs jQuery vs BackboneJS vs EmberJS)

TL; DR: AngularJS is awesome for building testable single page applications (SPA), and also data driven and CRUD apps. Show me the code!.

AngularJS motto is “HTML enhanced for web apps!”. That’s exactly what it does. It extends default HTML tags and properties to bind events and data into it using JavaScript. It’s a very different approach to other libraries such as jQuery, Backbone.js, Ember.js and similar… which follows the “Unobtrusive JavaScript” approach.

In the traditional unobtrusive JavaScript approach, instead of declaring the event handlers right in the element that they act upon, they are referenced using IDs and classes in the elements. That gives the advantage of separating structure (HTML) from behavior (Javascript). However, it doesn’t do any better on code complexity and readability.

Times have changed since then. Let’s examine closely how AngularJS tries to alleviate code complexity and readability.

  • Unit testing ready: JavaScript is usually very hard to unit test when you have DOM manipulations and business logic together (e.g. jQuery based code). AngularJS keeps DOM manipulation in the HTML and business logic separated. Data and dependencies are injected as needed.
  • DOM manipulation where they are used. It decouples DOM manipulation from application logic.
  • AngularJS is also great for single page applications (SPA).
  • Different browsers implements features differently, but fret not. Angular’s directive (or HTML extensions) take care of the differences for you.
  • Global name space: expressions and method definitions are scoped by controllers, so they don’t pollute the global name space.
  • Data models are plain old JavaScript objects (POJO).
  • Write less code: AngualarJS features like directives, filters and automatic data bindings save a lot of code. (More on that later ;)
  • Modularization and dependencies handlers are provided by AngularJS.

Despite all the goodness of AngularJS, it is not fit for every kind of project. Here’s some guidelines I used…

  • Need heavy DOM manipulations? Use jQuery or BackboneJS instead.
  • Data driven requirements (CRUD apps)? Use AngularJS.
  • Game programming? Use the canvas directly or game frameworks such as PhaserJS.
  • GUI editors? Use libraries with lower level abstractions such as jQuery.
  • Heavy RESTFul front-end app? Use Ember.js

Without further ado, let’s dive in!!

AngularJS

What is Angular.js?

Angular.js is a MVC open-source JavaScript web framework that facilitates the creation of single-page applications (SPA) and data driven apps. It’s not the single framework on its class, however it’s one of the most used and growing.

AngularJS Directives

The first concept you need to know about AngularJS is what are directives.

Directives are extensions of HTML markups in form of attributes, element names, CSS class and so on. When the AngularJS framework is loaded everything inside ng-app it’s compiled by Angular and the directives are bound to data, events and/or DOM transformations.

Notice two directive on the following example ng-app and ng-model.

Hello World in AngularJSlink
1
2
3
4
5
6
7
8
9
10
11
<html ng-app>
<head>
  <title>Hello World in AngularJS</title>
</head>
<body>

<input ng-model="name"> Hello {{ name }}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
</body>
</html>
  • ng-app: is a directive that bootstraps AngularJS and designates the element which have it as the root element. It’s usually placed on <html> or <body>.
  • ng-model: is a directive that binds form elements such as input, select, checkboxes, textarea or custom ones to a property called $scope. More on $scope and data binding in the next sections, for now bear in mind that the textbox value in the input it’s bound to {{ name }}
  • {{ name }} {{ }} are way of binding models to elements in HTML. In the example above the model name is bound to the placeholder {{ name }}. Play with the example bellow to see how the placeholder is updated real-time to whatever you type in the textbox.

Data binding AngularJS example:

See the Pen KdLaq by Adrian Mejia (@amejiarosario) on CodePen.

AngularJS Data Binding

Data binding is an AngularJS feature that automatically synchronizes your model data with your HTML. That’s great because models is the single-source-of-truth and you don’t have to worry about updating them. Here’s a graph from docs.angularjs.org.

Whenever the HTML is changed the model gets updated and wherever the model gets updated it is reflected in HTML.

AngularJS Scope

$scope it is an object that contains all the data to which HTML is bound. They are the glue your javascript code (controllers) and the view (HTML). Everything that is bound to the $scope, it is automatically $watched by AngularJS and updated.

Scopes can be bound to javascript functions and also you could have more than one $scope and inherit from outer ones. More on this in the controllers section.

AngularJS Controllers

Angular.js controllers are code that “controls” certain sections containing DOM elements in which they are declared. They encapsulate the behavior, callbacks and glue $scope models with views. Let’s see an example to drive the concept home:

AngularJS Controller Examplelink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body ng-controller="TodoController">
  <ul>
    <li ng-repeat="todo in todos">
      <input type="checkbox" ng-model="todo.completed">
      {{ todo.name }}
    </li>
  </ul>

  <script>
    function TodoController($scope){
      $scope.todos = [
        { name: 'Master HTML/CSS/Javascript', completed: true },
        { name: 'Learn AngularJS', completed: false },
        { name: 'Build NodeJS backend', completed: false },
        { name: 'Get started with ExpressJS', completed: false },
        { name: 'Setup MongoDB database', completed: false },
        { name: 'Be awesome!', completed: false },
      ]
    }
  </script>
</body>

AngularJS controller interactive example:

See the Pen spuCm by Adrian Mejia (@amejiarosario) on CodePen.

As you might notice we have new friends: ng-controller, ng-repeat and $scope.

  • ng-controller is a directive which tells angular what function controller to use for a particular view. Everytime AngularJS loads, it reads the ng-controller argument (in this case “TodoController”). Then, it will look for a function in plain old javascript object (POJO) with the same name or for angular.controller matching name.

  • $scope As mentioned earlier $scope’s are the glue between the data models in the controllers and the views. Take a look to our “TodoController” it has a parameter named $scope. AngularJS is going to pass ($inject) that parameter and whatever you attach to it, it will be available in the view. In this example is the particular is the todos array of objects.

  • ng-repeat as its name implies, it is going to “repeat” the element and sub-elements where this directive is declared. The number of times it’s going to repeat the elements it’s going to match the length of array in $scope.todos.

  • ng-model take a special attention to the checkbox with is bound to the todo.completed. If completed it’s true it’s going to be checked automatically and vice versa.

AngularJS Modules

Modules is a way to encapsulate different parts of your application (directives, controllers, factories, …) and reuse them easily. Here’s an example of how to rewrite our controller using modules.

AngularJS Module Examplelink
1
2
3
4
5
6
7
8
9
10
angular.module('app', [])
  .controller('TodoController', ['$scope', function ($scope) {
    $scope.todos = [
      { title: 'Learn Javascript', completed: true },
      { title: 'Learn Angular.js', completed: false },
      { title: 'Love this tutorial', completed: true },
      { title: 'Learn Javascript design patterns', completed: false },
      { title: 'Build Node.js backend', completed: false },
    ];
  }]);

Notice the <html ng-app="app"> in the example bellow

See the Pen uFfqG by Adrian Mejia (@amejiarosario) on CodePen.

Using modules brings many advantages such as modules can be loaded in any order, parallel dependency loading, tests can only load the required modules and keep it fast, clear view of the dependencies.

AngularJS Templates

Templates contains HTML and Angular elements (directives, markup, filters or form controls). They can be cached and referenced by an id.

Here’s an example:

AngularJS Template Exampledownload
1
2
3
4
5
6
7
8
  <script type="text/ng-template" id="/todos.html">
    <ul>
      <li ng-repeat="todo in todos">
        <input type="checkbox" ng-model="todo.completed">
        
      </li>
    </ul>
  </script>

Does the code inside looks familiar? ;)

Notice they are inside a script and has a type text/ng-template.

AngularJS Routes (ngRoutes)

ngRoutes module allows changing what we see in the app depending on the URL (route). It usually uses templates to inject the HTML into the app.

It doesn’t come with AngularJS core so we have to add it as a dependency. So, we are going to get it from Google CDN:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.min.js"></script>

Let’s say that in our todo app we want to add notes to each one. So let’s do that using routes!

1
2
3
4
5
6
7
8
angular.module('app', ['ngRoute'])
  .config(['$routeProvider', function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: '/todos.html',
        controller: 'TodoController'
      });
  }]);

See the Pen CmnFH by Adrian Mejia (@amejiarosario) on CodePen.

  • First notice that we removed ng-controller="TodoController" from the body tag. The controller we be called based upon the route.
  • ngView is a directive used by $route to render HTML into it. Everytime the route changes, it also updates the ngView.

AngularJS Services (factory)

Notice that if you want to create a 2nd controller and share $scope.todos it is not possible right now. That’s when services become handy. Services are a way to inject data dependencies into controllers. They are created through factories. Let’s see it in action:

AngularJS Service Factory Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  angular.module('app', ['ngRoute'])

    .factory('Todos', function(){
      return [
        { name: 'AngularJS Directives', completed: true },
        { name: 'Data binding', completed: true },
        { name: '$scope', completed: true },
        { name: 'Controllers and Modules', completed: true },
        { name: 'Templates and routes', completed: true },
        { name: 'Filters and Services', completed: false },
        { name: 'Get started with Node/ExpressJS', completed: false },
        { name: 'Setup MongoDB database', completed: false },
        { name: 'Be awesome!', completed: false },
      ];
    })

    .controller('TodoController', ['$scope', 'Todos', function ($scope, Todos) {
      $scope.todos = Todos;
    }])

We are now injecting the data dependency Todo into the controllers. This way we could reuse the data to any controller or module that we need to. This is not only used for static data like the array, but we could also do server calls using $http or even RESTful $resource.

Let’s say we want to show the details of the task when we click on it. For that, we need to create a 2nd controller, template and route that uses this service:

See the Pen pGkhg by Adrian Mejia (@amejiarosario) on CodePen.

(NOTE: Click on the links and it will take you to the todo details. Use backspace key to go back to main menu)

This is what is happening:

  1. In the HTML tab we created a second template /todoDetails.html which contains the todo details we want to show.
  2. Also, in our previous template /todos.html we want to have a link that points to the todo detail. We are using the $index which is the corresponding order number in a ng-repeat.
  3. In the JS tab we created a new $routeProvider which points to a new controller TodoDetailCtrl and the template that we created on #1. The :id parameter it’s accessible in the controllers through $routeParams.
  4. Created the new controller TodoDetailCtrl and inject the dependencies which are $scope, Todos (factory), and $routeParams which will have the id param.
  5. Set the $scope in the new controller. Instead of using the whole array, we are going to select only the one that we need using the id that we set in step #2.

NOTE: in codepen you won’t see the URL, but you can download the whole example an open it from here.

AngularJS Filters

Filters allows you to format and transform the output of expressions inside the curly braces. AngularJS comes with a bunch of useful filters.

Built-in Filters:

  • filter: search for a given string in an array and return matches.
  • Number: adds comma separated 1000’s and 2 decimal places.
  • Currency: the same as Number and adds a $ in front.
  • Date: takes a unix timestamp (e.g. 1288323623006) or date string and output it in the format that you specify (e.g. ‘longDate’ or fragments ‘yyyy’ for 4 digit years). For a full list see here.
  • JSON: converts javascript objects to JSON strings.
  • lowercase/uppercase: converts strings to lowercase/uppercase.
  • limitTo: number of elements from an array to show.
  • orderBy: order array of objects by key that you specify.

Note you can also chain multiple filters and also define your own filters.

See the Pen tyuDK by Adrian Mejia (@amejiarosario) on CodePen.

After a while using our Todo app it will become a large list of item and we might what to search to find them easily. Let’s use a filter to solve that problem.

1
2
3
4
5
6
7
8
9
  <script type="text/ng-template" id="/todos.html">
    Search: <input type="text" ng-model="search.name">
    <ul>
      <li ng-repeat="todo in todos | filter: search">
        <input type="checkbox" ng-model="todo.completed">
        <a href="#/"></a>
      </li>
    </ul>
  </script>

Notice that we are using search.name in the ng-model for search. That will limit the search to the name attribute and search.notes will look inside the notes only. Guest what search would do then? Exactly, search in all the attributes. For the following example and try it out:

See the Pen ahwbz by Adrian Mejia (@amejiarosario) on CodePen.


ng-knowledge

Congrats, you have reach this far! It’s time to test what you have learned. Test Driven Learning (TDL). Open this file on your favarite code editor. Copy the boilerplate code and built the full app that we just build in the previous examples. Of course, you can take a peek from time to time if you get stuck ;)

Download this file as…:

index.html

-OR-

Fork and edit online:

See the Pen degzC by Adrian Mejia (@amejiarosario) on CodePen.

What’s next?

We are going to build upon the things learned in here, in the next post we are going to setup a backend in NodeJS and MongoDB and connect it to AngularJS to provide a full featured CRUD app. Stay tune for the next two posts:

  • Creating API with NodeJS, ExpressJS and MongoDB tutorial for beginners
  • Full CRUD AngularJS app with NodeJS and MongoDB

I also have created BackboneJS tutorials check it out:

How Company X Make Money?

| Comments

Have you ever wonder how the companies that offer free services make money? Such as Instagram, Evernote, Facebook, Twitter, LinkedIn, Google Maps, so on… or if it is even profitable to keep free users using their services. We would go through several revenue models and hopefully, it will throw you some light next time you decide to roll your own startup.

TL; DR: Go to the interactive company revenue checker.

Revenues Models

Let’s start first giving some perspective what models are actually giving the most revenues. In 2013, App Store, reported that free apps brought the 71% of the revenue! Even more than paid apps… how’s that even possible!?

(source: techcrunch )

Ok, let’s discuss some revenue models to understand this. There are 3 main models

  • Freemium: apps are free to download and use. However, quite often some different features are sold separately (e.g. new levels, specialized functions, remove ads, more capacity, and so on). E.g. Pandora, Hulu, Google Docs.

  • Premium: users paid upfront a fixed price for the application. After you pay for it, you are able to download it. Usually new software updates are free. E.g. MS Office 365.

  • Subscription: users paid a fixed price which is automatically charged every certain time. Magazines in the iOS Newsstand are a good example of this subscription based model. Subscriptions have generally lower prices than premium accounts. E.g. Netfix.

Freemium is not as “free” as it might seem in the surface, there are indirect ways of getting revenues from it.

  • Advertising: the application/service is free to use, but it contains ads or interruption banners for an couple of minutes in order to raise revenue. This model is usually applied along with freemium apps and to remove the ads users have to pay a subscription. E.g. Spotify.

  • Selling data: user information and behavior inside the application is sell to interested 3rd-parties. Usually used with freemium apps and specified in the terms of used.

  • Transaction: the application is free to use generally and charges a percentage or fixed fee with every users’ transaction made. For example, it allows you to publish your item on their site for free but when you sell it, it charges you a fee. Or publish a project in a site and when it reaches certain goal a percentage fee is applied. E.g. eBay, Kickstarter.

  • Online lead generation: collects user’s information sometimes in an exchange of a product or service and then resell the information to companies interested indirectly. It’s different from the selling data model because the information is not sold to 3rd party directly, but indirectly. Influencing users desitions based on 3rd party companies affiliated and users’ interests, likes and behaviors. E.g. Mint, LinkedIn.

  • Donations: (it’s self-explanatory) Services/apps are free, but it encourages users to contribute throughout donations to support the development.

After reading these, you might have more clues why free apps are so much win nowadays. They helped to create those million-dollar-per-day games! (remembered FlappyBird, Candycrush, Farmville…) In a market where there is enough competition, having a free option will take you to large numbers of users quicker and broader, because of the low barrier to entry. For instance, Whatsapp had at certain point 10k of daily downloads, after moving it to $1 it download rate drops 10 times, they finally opted for yearly subscriptions.

Subscription-based revenue are also a model worth doing a special mention. It brings a steady flow of income to companies and usually comes in different tiers to fulfill users need. But, it has to be flexible enough, because it might limit hard core users which might be willing to pay more for taking the product to a new level.

Click at the companies logos to see if their revenue models are profitable or not. You might get surprised! If some information is not accurate please leave a comment and if you are wondering about another company not listed here, let me know and I will add it :)

    Cheap Airplay Receiver With Raspberry Pi

    | Comments

    I got excited about the idea of having a Raspberry Pi. It is in essence one of the smallest complete computer that you can get for $35 bucks! Ok, after I got one I had to do something useful with it… So I make it a Airplay receiver to play music remotely from any of my apple devices!

    There is a couple of ways to make it work. The easiest one is to install the RaspBMC, a popular media center.(http://www.raspberrypi.org/downloads) You can even turn it into a home theater (http://www.makeuseof.com/tag/raspberry-pi-home-theater-system/). However, I’m not going to explain any of those ways because just installing them gives you 99% of the functionality. As a developer, I want to have control of the computers, and I’m not afraid of the console. So, I installed Raspbian instead, which is a lightweight Ubuntu/Debian Linux optimized for Raspberry Pi.

    Getting started

    1. Install Raspbian “wheezy”

    Download the image from http://www.raspberrypi.org/downloads and follow the instructions. You have to format the SD card and “copy” the image. You can download this formatting tool: https://www.sdcard.org/downloads/formatter_4. After that, plug the SD card in Raspberry, also the Ethernet cable and power cord. For more instructions follow http://lifehacker.com/5976912/a-beginners-guide-to-diying-with-the-raspberry-pi.

    2. Setup Pi

    You need to connect it to an HDMI display to set it up using a USB mouse and keyboard or you can use SSH if you had set that up.

    3. Access the Terminal

    From the terminal type the following commands in you Raspberry Pi:

    Become root and update the system

    1
    
    sudo apt-get update && sudo apt-get upgrade
    

    3. Setup Audio

    Audio ports could either be bind to the HDMI connection or to the audio output jack (you need sudo to execute any sound command).

    1
    
    sudo amixer cset numid=3 1
    

    Connect the speakers to you Raspberry Pi. You can test that they work with these:

    1
    2
    
    sudo speaker-test -t pink -l 1
    sudo speaker-test -t sine -l 1
    

    You can also adjust the volume

    1
    
    sudo alsamixer
    

    4. Install Airplay software

    I tested with 2 different programs, both of them did the trick for me.

    The latter is more popular so I will give the instructions for that one:

    1
    2
    3
    4
    5
    6
    
    apt-get install -y libssl-dev libavahi-client-dev libasound2-dev git
    git clone https://github.com/abrasive/shairport.git
    cd shairport
    ./configure
    make
    ./shairport -a 'AirPi'
    

    5. Run Airplay (shairport) on boot.

    It’s nice to run airport receiver automatically when you connect your Pi.

    Create a file to start shairport

    1
    
    nano /etc/init.d/airplay
    

    Type the following into airplay:

    airplay
    1
    2
    
    #!/bin/bash
    /usr/local/bin/shairport -a "AirPi"
    

    Close the editing mode and exit the file. Then register the script to be run on boot.

    1
    2
    
    chmod a+x /etc/init.d/airplay
    update-rc.d airplay defaults
    

    Reboot your Pi and you are good to go! (If you have any questions you can write a comment below)

    Algorithms for Dummies (Part 1): Big-O Notation and Sorting

    | Comments

    After being developing software for a while, I realized that there is a couple of ways to become better at it. One it’s through your experience: writing code, working on projects, getting hands dirty… Other one it’s learning algorithms and design patterns. In other words through leveraging the experience of other computer scientists. Learning to use algorithms efficiently can instantly add to you the equivalent of 10 years of experience or more. Let’s get started and add new tools to our arsenal!

    How do you know a piece of code that you just wrote is good enough? When you modify a program, how do you know if it is better as you found it? How do scale programs to handle huge amount of data? In fact, You cannot improve what you can’t measure.

    How to measure them? We could count the number of seconds it takes to execute and compare it with other one. However, it’s not just troublesome to timers around code but if we run it in different hardware (e.g. supercomputer) it will seem like more efficient when indeed it’s exactly the same program. Let’s illustrate a better way with an example. Let’s say you want to sort an array of n integers.

    Sorting Algorithms

    1
    2
    3
    4
    5
    6
    7
    8
    
      void sort(int[] arr){
        for(int x=1; x < arr.length; x++)
          for(int y=x; y > 0 && arr[y-1] > arr[y]; y--){
              int t = arr[y];
              arr[y] = arr[y-1];
              arr[y-1] = t;
            }
      }
    

    Do you recognize this algorithm? It’s called Insertion sort. It has two nested loops, which means that as the number of elements n in the array arr grows it will take approximately n * n longer to perform the sorting. In big-O notation, this will be represented like O(n2). More on this notation later.

    What would happen if the array arr is already sorted? That would be the best-case scenario. The inner for loop will never go through all the elements in the array then (because arr[y-1] > arr[y] won’t be met). So the algorithm in run in O(n).

    We are not living in an ideal world. So O(n2) will be probably the average time complexity. Can you think a better way of sorting an array of elements?

    Take some minutes to think and come back…

    Merge Sort

    A more efficient algorithm is the Merge sort. It uses the principle of divide and conquer to solve the problem faster. The idea is the follows:

    • Divide the array in half
    • Divide the halves by half until 2 or 3 elements are remaining
    • Sort each of these halves
    • Merge them back together

    Can you determine the time complexity of mergesort?

    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
    
      void sort(int[] arr){
        int[] helper = new int[arr.length];
        mergesort(arr, helper, 0, arr.length-1);
      }
    
      void mergesort(int[] arr, int[] helper, int low, int high){
        if(low < high){
          int middle = (high+low)/2;
          mergesort(arr, helper, low, middle);
          mergesort(arr, helper, middle+1, high);
          merge(arr, helper, low, middle, high);
        }
      }
    
      void merge(int[] arr, int[] helper, int low, int middle, int high){
        for (int x=low; x <= high; x++) {
          helper[x] = arr[x];
        }
    
        int left = low;
        int curr = low;
        int right = middle+1;
    
        while(left <= middle && right <= high) {
          if(helper[right] > helper[left])
            arr[curr++] = helper[left++];
          else
            arr[curr++] = helper[right++];
        }
    
        while(left <= middle)
          arr[curr++] = helper[left++];
      }
    

    Even though the code is much longer, the algorithm is much more efficient.

    It would take some more knowledge to derive the running time mathematically, and we haven’t covered that yet. However, bear with me, it’s O(n log(n)). Let’s sum up:

    Algorithm best average worst space complexity
    Insertion Sort O(n) O(n2) O(n2) O(1)
    Merge sort O(n log(n)) O(n log(n)) O(n log(n)) O(n)

    Notice that the table has also the space complexity. How much space does the algorithms take is also an important parameter to compare algorithms. The merge sort uses an additional array that’s way its space complexity is O(n), however, the insertion sort uses O(1) because it does the sorting in-place.

    Big O Notation

    Big O is defined as the asymptotic upper limit of a function. In plain english, it means that is a function that cover the maximum values a function could take. As we saw a little earlier this notation help us to predict performance and compare algorithms.

    Growth RateName
    1Constant
    log(n)Logarithmic
    nLinear
    n*log(n)Linearithmic
    n^2Quadratic
    n^3Cubic
    2^nExponential

    This is kinda abstract let’s see what it means in code:

    Growth RateNameCode e.g.description
    1Constanta+=1;statement (one line of code)
    log(n)Logarithmic
    while(n>1){
      n=n/2;
    }
    
    Divide in half (binary search)
    nLinear
    for(c=0; c<n; c++){
      a+=1;
    }
    
    Loop
    n*log(n)LinearithmicMergesort, Quicksort, …Effective sorting algorithms
    n^2Quadratic
    for(c=0; c<n; c++){
      for(i=0; i<n; i++){
        a+=1;
      }
    }
    
    Double loop
    n^3Cubic
    for(c=0; c<n; c++){
      for(i=0; i<n; i++){
        for(x=0; x<n; x++){
          a+=1;
        }
      }
    }
    
    Triple loop
    2^nExponentialTrying to braeak a password generating all possible combinationsExhaustive search

    That’s all for this first part 1. I will continue publishing this tutorials every week or so. Stay tune!

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

    | Comments

    BackboneJS IV

    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 RouterFull 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 routerFull 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.AppViewFull 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.TodoListFull 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’ linksFull 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!