Part 5 of n: Using Backbone JS to create application

In this article we will create a single page application using BackboneJS.

Backbone.JS is a simple JavaScript library and un-opinionated. My reason for choosing Backbone.JS is its simplicity and its ease of development.

Below is the heat-map visualization for Manhattan from the application 🙂

Manhattan-Heat map

Manhattan-Heat map

Please have a look at how the application is structured here: https://github.com/tarun11ks/NYCTaxi/tree/master/js

This structure is how application is made modular. I learned from this excellent tutorial: http://backbonetutorials.com/organizing-backbone-using-modules/. It nicely explains the use of require.js which is what is making the application modular. I would recommend looking at the boilerplate code of the tutorial here: https://github.com/thomasdavis/backbonetutorials/tree/gh-pages/examples/modular-backbone. The article is a little outdated but the concept remains the same.
Googling “Backbone js boilerplate” will give you more examples.

Another great article here: http://addyosmani.github.io/backbone-fundamentals/#modular-development

The modular concept revolves around the use of “require.js“. Together with AMD it provides better dependency management with asynchronous loading of scripts.

This post won’t explain about the above concepts as the linked websites provide great deal of information.

Libraries(not the obvious ones) used:
Hyperlapse.js -> To show animated google street view. It requires other libraries as it’s dependencies- Three.JS and GSVPano.JS
Backbone.viewcache -> To keep cache of views to be reused. Currently used for Hyperlapse.

I will briefly explain the components.
index.html:
The script tag in the header calls the main.js function which starts our application.

The body has navigation menu(using Bootstrap) and a div container to load the views inside it.

Model:

define([
	'backbone'
], function(Backbone) {
	var taxiAgg = Backbone.Model.extend({

	});

	return taxiAgg;
});

A simple model that represents a MongoDB document of “aggLocations” collection.

Collection:

define([
	'backbone',
	'model/TaxiLocAgg'
], function(Backbone, taxiModel) {
	console.log('inside Collection');
	var taxis = Backbone.Collection.extend({
		model: taxiModel,
		url: function() {
			// Use fragment to construct url.
			var state = Backbone.history.fragment;
			if (state)
				return 'http://localhost:2387/' + state;
			else
				return 'http://localhost:2387/manhattan'
		}
	});

	return taxis;
});

A simple Backbone collection with 2 properties: model and url. The model being referenced is TaxiLocAgg.js.
The url property is very crucial. It uses the Backbone’s fragment to determine which borough’s records are needed to be fetched.
These fragments are defined in the routes of the router.js file. Using this technique, we constructed a dynamic url call without needing to create separate collection for each borough.

– GoogleMapsApiLoader.js

// https://gist.github.com/MattSurabian/7868115
var google_maps_loaded_def = null;

define(['jquery'], function($) {
	if (!google_maps_loaded_def) {
		// Create a deferred object. Sets status to pending.
		google_maps_loaded_def = $.Deferred();

		// Executes after API authentication is successful.
		window.google_maps_loaded = function() {

			// Resolve the deferred object. Executes done callback.
			google_maps_loaded_def.resolve(google.maps);
		}

		require(['https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE&callback=google_maps_loaded&libraries=visualization'], function() {}, function(err) {
			google_maps_loaded_def.reject();
			throw err;
		});
	}

	// Returns deferred's promise object.
	// Provides ability to only attach handlers or determine the state.
	return google_maps_loaded_def.promise();
});

I was searching online on how to use google maps with our modular application. You must get your own key from here. Finally found this gem which uses jQuery’s deferred function. The same is used in jQuery’s ajax calls too. Using jQuery’s deferred along with promise object helps eliminate the callback hell.
When calling the GoogleMapsApiLoader module, first it creates the deferred object(goes into pending state), validates the API key and when successful, it calls the callback google_maps_loaded which then calls resolve on the deferred object to signal that the google.maps object is instantiated and ready to be used. The promise object is a kind of an abstraction of deferred, once resolved, any done callbacks attached to it gets called. If the api validation fails, then deferred’s reject is called which will call any fail callbacks attached to the module. We will see it in more detail in the MainView.js section below.

MainView.js:
This Backbone view is responsible for showing the google heat maps visualization.
The GoogleMapsLoader object of the GoogleMapsApiLoader module attaches callbacks “done” and “fail” to the promise object. When the api key in the module is resolved, the promise object invokes the done callback which then calls the collection to “fetch” the records using the url. Once that is successful, we create an array of longitude and latitude that google.maps understands and finally the heat map visualization is constructed!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s