Is your Javascript waiting on multiple Backbone fetches?

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.

Making promises

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.


Git Rebase destroyed your commit? Reflog to the Rescue!

I admit I’m something of a newb when it comes to the distributed source control system, Git. This came as a shock to me because I consider myself fairly competent working with Mercurial. When I got a “rebase already started” error message while preparing to submit my latest changes, I didn’t much know what to do about it.

Thinking the message was a leftover from a particularly ornery merge I had just performed on a prior issue, I tried running

$ git rebase --abort

and submitted the command. The local changes, the revisions I pulled from the server, and the commit for my most recent issue were all gone. Notice that last bit? I didn’t want that. Wonderful. Ensue frantic Googling.

That’s how I discovered git reflog. A command whose help text summary suffers from Git’s notorious documentation:

$ git help reflog
git-reflog - Manage reflog information

As I understand it, the reflog is like an activity stream of changes that happen to your repository. Fortunately, this means that in almost every instance, you can use it as a way to recover commits that you’ve lost while navigating the myriad of history manipulating commands that see common usage in Git, such as rebase. In this case, I found my commit:

$ git reflog show
...
483f7d0 HEAD@{18}: commit: DEV-1297 - Expand last viewed widget on home page
...

Now what’s cool about this listing, is that you can checkout these refs as if they were branches. If you want, you can even give it a name.

$ git checkout 483f7d0
$ git checkout -b DEV-1297_Recovered_Commit

And from this branch my commit is restored and I can get back to work!


Participating in the White House’s Summer Jobs+ Code Sprint

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

I set out to write a demo application to see what it would look like. This gave me an opportunity to practice jQuery and JavaScript, as I do very little front-end web development at work. I also took the opportunity to try out PHP. Even though I work professionally in a Microsoft stack, I chose PHP for the demo because I wanted to learn something new and I wanted the final result to be a site I could easily zip up and email to somebody without a lot of fuss about deployments. The code sprint lasted for two weeks (it had been extended from one and I feel that even two was too short), but there were only four days that I worked on it in, the evenings after I got off of work.

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.

Web application screenshot

Retrospective

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.

Attached Source Code

NY Jobs Plus