I’ve been working with Backbone for approximately a month now. I’m a fan of using a structured coding practice to untangle your objects and the DOM.
In Backbone, you get the latest state of your model by fetching it from the server. You can set a callback on the fetch function directly or by binding to the collection’s reset event.
Tracking fetched collections manually
I needed to fetching more than one collection at the same time and call a callback when all of the fetches were finished. My first attempt wasn’t very good. I’ll give you a largely trivialized sample of what I had going on.
This is an example of a view written in CoffeeScript. I want to fetch 3 different collections, render them using Handlebar templates, and call a function when all 3 collections are rendered:
initialize: => @apples = new MyModels.Apples @oranges = new MyModels.Oranges @bananas = new MyModels.Bananas @bindTo(@apples, 'reset', @renderApples) @bindTo(@oranges, 'reset', @renderOranges) @bindTo(@bananas, 'reset', @renderBananas) render: => @apples.fetch() @oranges.fetch() @bananas.fetch()
This actually isn’t bad so far. We create our models and bind an event so that when they are fetched, their respective render functions will be called. The real mess came later in the same file.
renderBananas: => @$el.html(HandlebarsTemplates["bananas"]( bananas:@bananas.toJSON())) Backbone.ModelBinding.bind(this) @bananasLoaded = true @finishLoading() finishLoading: => return unless @applesLoaded return unless @orangesLoaded return unless @bananasLoaded alert("All collections loaded!")
For brevity, I left off renderApples and renderOranges. Those functions are identical to renderBananas with their respective fruits substituted in. This solution isn’t very scalable, as we need to create more state variables to track any new collections that get added in the future and make sure we account for those variables when we finish loading.
It would be better if we could define a callback that would wait for all of my fetch calls to finish. It would be even cooler if these things chained together.
What I needed to be using are jQuery Deferred Objects. See, Backbone server calls (like fetch and save) are just $.ajax() calls under the hood, and since jQuery 1.5, $.ajax() calls implement an immutable version of Deferred Object called a Promise. As it happens, everything in that code sample is already defer-able.
I’ll modify the view to make use of Promises.
initialize: => @apples = new MyModels.Apples @oranges = new MyModels.Oranges @bananas = new MyModels.Bananas # Dropped the bind calls, we won't be needing them! fetchCollections: => # Combines these individual promises into one. $.when( @apples.fetch(), @oranges.fetch(), @bananas.fetch() ).promise() renderCollections: => $.when( @renderApples(), @renderOranges(), @renderBananas() ).promise() renderBananas: => d = @$el.html(HandlebarsTemplates["bananas"]( bananas:@bananas.toJSON())) Backbone.ModelBinding.bind(this) d.promise() finishLoading: => alert("All collections loaded!")
With all of this in place, the render function shown below is remarkably straightforward, and communicates the behavior of the view beautifully!
render: => @fetchCollections() .then(@renderCollections) .then(@finishLoading)
This function is so much better than before; it tells me everything that’s going to happen in a clean and concise way.
An additional enhancement I’ve snuck in was to return promises for my .html() calls in the renderBananas function. Now I know that my HTML templates will be rendered before finishLoading gets called. This will protect me from making a mistake like attempting to focus() an element that maybe hasn’t been rendered yet.
Two weeks ago I read about the Code Sprint being put forth by the White House asking developers to write cool applications demonstrating their new Summer Jobs+ API. The sprint officially ends tomorrow, April 16th, but regretfully I won’t be submitting an application. This post is a story about the application would have been if I did have a submission.
The Summer Jobs+ Code Sprint
Two weeks ago, I read the post on the White House’s blog challenging developers to participate in the code sprint. And it’s not like I make a habit of reading a blog about the residence of the first family and looking for programmer stuff–I had been directed there by an article about the code sprint from the Associated Press.
My coworkers helped me brainstorm the initial idea for the proejct, which was to connect the job listings from the Summer Jobs+ Bank with the NYC public transportation information available through NYC OpenData. I wanted to make the assumption that there would be youths that would not have access to a car and needed information about job listings that would be “within walking distance of your house” or “this is the bus route you would take”.
I know it seems a little weird for a dude based out of Kansas City, Missouri who has never even been to New York to select this kind of project. However, I was already aware of NYC’s efforts to provide a great deal of city information to the public through the OpenData project, including up-to-date statistics on bus and subway routes. New York City seemed like a good city to set up a demonstration and, if the idea had traction, more cities could be added over time.
The idea for the site was meant to be simple. You would enter your address and a keyword or two about the kind of job you were looking for. The server would pull the matching listings from the Summer Jobs+ Bank and annotate them with recommendations about how to reach the listing based on NYC’s OpenData information.
The working title for the application was NY Jobs+.
Designing my Application
The goal of the first evening was to authorize successfully and be able to make a basic request and print out the raw JSON to the screen. I didn’t anticipate much trouble implementing their authorization scheme, as it is similar to APIs I’ve integrated with at work. Though I was certain that I had followed the specification to the letter, I was always getting error responses from the server. Exhausted from debugging the issue, I emailed the site administrator. Turns out the API had been taken off-line for an update.
The next day, my site came to life because the API was back online. The Department of Labor’s documentation is well-formatted when it comes to formatting the request, but there is absolutely nothing about the payload you get back. So the second evening was spent figuring out how to parse the resulting JSON for some pieces of information that I wanted to display and render it on my page as a table.
By the end of the third evening, I had a style sheet and could search for jobs in New York based on a keyword entered by the user, displaying the results in a template-driven accordion widget using jQuery UI.
On the fourth day, I wanted to render the location of the job listing on a map. That was, unfortunately, when the whole thing began falling apart. While the schema for the job listings states that the jobLocation is a required field, the actual data only provides the City, State, and Zip Code. No street address. The data wasn’t actually there. The entire premise of the application was not achievable.
What could I have done differently? Surely more due diligence while requirements gathering to confirm that the information I needed would be present. But in my own defense, the schema does contain entries for street addresses. Heck, the schema has entries for GPS coordinates!
Even though I didn’t accomplish the goal I wanted to with this project, it’s not a complete loss. At work, I mostly deal with server-side code in C#. So I got a chance to refresh my memory on web development and I got the chance to explore technologies I’m not as familiar with, such as jQuery and PHP.
I’m making the source code available as an attachment at the bottom of this post.
To run it, you’ll need a web server that supports PHP (The built-in server, started from the command-line switch, “php.exe -S localhost:80” works just fine for testing) and to enable the cURL extension in your PHP configuration file if it isn’t already enabled.