As a way to teach myself Backbone.js, I made a Backbone app built on top of the Rotten Tomatoes API. Basically, you can search for movies instantly and read some basic info on each one.

Initially, I thought I was going to make this post interesting. But it’s late and I’m lazy, so I’m just going to copy paste some JS code in here.

Setting up the App

This was actually the most frustrating experience of the whole thing. I used require.js for this and had a touch time because I forgot to setup my dependencies correctly (More on that in a bit).

How my setup looks:

folderStruc

In the index.html, I have this:

<script type="text/javascript" src="js/lib/require.js" data-main="js/app"></script>

This tiny little line of code starts up my whole app. It includes require.js and then tells require js what .js file to look for in order to start the app. So in this case, my app will look for js/app.js for further instrucitons.

In app.js we find this:

// Configure loading modules from the lib directory,
     // except 'app' ones,
     requirejs.config({
          "baseUrl": "js/lib",
          'urlArgs': "bust=" + (new Date()).getTime(),
          "paths": {
          "app": "../app"
     },
     shim: {
          "backbone": {
               //These script dependencies should be loaded before loading backbone.js
               deps: ['underscore', 'jquery'],
               //Once loaded, use the global 'Backbone' as the module value.
               exports: 'Backbone'
          },
          "underscore": {
               exports: '_'
          },
     }
});

So, here we first include a ‘baseUrl’ which will contain all our libraries. In this case, that’s ‘js/lib/’ which contains backbone.js, jquery.js, less.js (not used through require.js), require.js, and underscore.js. We tell requires.js to expire the application immediately for development purposes. Then specify our app directory js/app/.

Finally (and this is where I got stuck for a bit), we establish dependencies and namespaces. Backbone requires jquery and underscore. Similarly, underscore requires jquery. So we tell require to load them accordingly. We also declare our namespaces ( Backbone for backbone and _ for underscore).


// Load the main app module to start the app
requirejs(["app/main"]);

We’re finished with this file. Require.js has loaded all our dependencies and has started to load our app. Where exactly is our app again? That would be in js/app/main.js! Let’s take a look.

Now, really this is where the magic happens and all we have to do in order to get started is this:

 


// Setup some requirements. Jquery and Underscore are requiremetns for backbone
require([
     'jquery',
     'underscore',
     'backbone',
], function($, _, Backbone){
     // Some Asome Javascript that will change the world
});

Now we have all the components we need to start writing some functionality. In this case, we’ll start at the end ouf our code with the router.

The Router


function($, _, Backbone){
     // Some Asome Javascript that will change the world
     /* YOUR MODELS */
     // ...200 lines of code laters
     /* YOUR VIEWS */
     // ...300 lines of code later
     /* YOUR ROUTER */
     var Router = Backbone.Router.extend({
          routes : {
               "movies/:id": "getMovie",
               "search/:query": "search",
               "not-found": "notFound", // For when we can't find something
               '*path': 'defaultRoute', // Our last resort, go home
          },
          defaultRoute : function() {
          },
          notFound : function(){
          },
          search : function(this_query_term){
          },
          getMovie : function(id){
          }
     }
});
});

This is our router. It basically sniffs out our changes, matches different patterns for it, and redirects to a url accordingly. It’s pretty cool. In this case, when we go to a home page, it will fire up ‘defaultRoute’, because there isn’t anything in the url. If it find movies/23423 it will pass on that number to the getMovie function, in order for it to use it.

Search

Pugalicious33

The user first encounters the site through the search box.

In Backbone this is described as follows:


// A separate view for search
SearchView = Backbone.View.extend({
// Tied to an element in the DOM
el: '#search_container',
// Tied to a template
template: _.template($("#search_template").html()),
initialize: function(){
	// Render on init
	this.render();
},
render: function(){
	// We don't pass any variables here
	this.$el.html(this.template());
	return this;
},
events : {
	// We bind certain events to a custom function, which looks for movies in the API
	"change" : "query_movies",
	'click .submit' : "query_movies",
},
query_movies : function(){
	// Using jquery, find the query term
	var this_query_term = $(this.el).find('.search-box').val();
	// Push the query term to the router
	router.navigate('search/' + encodeURIComponent(this_query_term) , true);
}});
// Down Below, we initiate this view 
// By default, we init our search and our router
var serch_view = new SearchView();
var router = new Router();
// URLs don't work without this
Backbone.history.start();

We have initiated this view on init, along with our router and our Backbone.history (which takes care of push states). This will render out our view and bind any changes in search to the router.

The event would go something like this:

1. Page is loaded

2. Search view is loaded, html is added, and element is binded

3. A search is entered

4. The query_movies function (inside the search view) is triggered

5. the query_movies function calls the router

6. The router redirects the app to search funciton, feeding it the query variable

7. A query to the API is made and returned

8. A collection is made

9. That collection is rendered, appended to the html and binded

On a later episode of this great blog, I will talk a bit more about collections, models and a bit more about views. In the mean time, you can checkout this app and checkout the repo on github.com.