Using a RESTful API in Backbone

In the previous chapter, we created a self-contained, in-browser web application using localStorage to persist data. Now we have a server set up to sync that data to disk instead, allowing our app to be used in any browser on potentially any machine. All we have to do is adapt our code.

We need all of the same external dependencies as in the previous chapter, so let’s start by installing the same Bower modules as before:

 $ ​​bower​​ ​​init
 $ ​​bower​​ ​​install​​ ​​--save​​ ​​jquery
 $ ​​bower​​ ​​install​​ ​​--save​​ ​​backbone

Now on to our Backbone models and collections. We no longer need the initial data or the Backbone.sync shim from the previous chapter. All we need to do to tell Backbone how to talk to our RESTful API is attach a url value to each collection and model. Here’s how our collection definitions look with that addition:

 class​ window.BoardCollection ​extends​ Backbone.Collection
  model: Board
  url: ​'/boards'
 class​ window.ColumnCollection ​extends​ Backbone.Collection
  model: Column
  url: ​'/columns'
 class​ window.CardCollection ​extends​ Backbone.Collection
  model: Card
  url: ​'/cards'

When we call the fetch method on a collection, Backbone will make a GET request to that URL. Additionally, when we call save on a model, Backbone cleverly infers the URL to POST or PUT to based on the URL of the collection that the model belongs to. So there’s no need to modify our models at all.

We need to make only a few more adjustments. In the localStorage-based version of the project, we were able to synchronously load all of our data. Now any action we perform is asynchronous. The leap from synchronous operations to asynchronous ones has many implications in a web application, and in fact I’ve devoted an entire book to the subject.[51]

The first problem is that we need to fetch the data for our three collections and parse it in a specific order: first cards, then columns, then boards. This is because our column models reference card models, and board models reference column models. So how do we do this without waiting for three sequential requests?

The answer is to make the requests in parallel and then parse the data in sequence. We can do this by telling our collections to fetch the data without parsing it. Each fetch will return a jQuery promise representing the Ajax request, so we can use jQuery’s $.when to execute a callback only after all three requests have been completed. Each argument passed to the callback will consist of an array of the arguments that would be passed to that Ajax request’s success handler. Of those, we care about only the first argument, the data. Here’s the code:

 # Fetch all card, column, and board data in parallel, then parse in sequence
 fetchInitialData = $.when(
 new​ window.CardCollection().fetch(parse: false)
 new​ window.ColumnCollection().fetch(parse: false)
 new​ window.BoardCollection().fetch(parse: false)
 )
 
 fetchInitialData.then ([cardData], [columnData], [boardData]) =>
  options = {parse: true}
  window.allCards = ​new​ window.CardCollection(cardData, options)
  window.allColumns = ​new​ window.ColumnCollection(columnData, options)
  window.allBoards = ​new​ window.BoardCollection(boardData, options)
  renderBoard()
 return
 
 renderBoard = =>
 # Display the last board as the page
  board = window.allBoards.last()
  $board = $(​"<div class='board' data-board-id='​​#{​board.get(​'id'​)​}​​'></div>"​)
  $(​'body'​).append $board
  boardView = ​new​ window.BoardView(
  model: board
  el: $board
  ).render()

The second problem is that we need to save new cards and columns in two places (the new object and the existing object that references it), and once again, order matters, because the new object’s ID is assigned by the server—there’s no way to save a reference until after the new object has been saved. So when we add a new card or column, we have to take these two steps in sequence:

 addColumnClickHandler: (e) ->
  newColumn = ​new​ window.Column({}, {parse: true})
  allColumns.add(newColumn)
  newColumn.save().then =>
  @model.get(​'columns'​).add(newColumn)
  @model.save()
  @render()
 return
 return
 addCardClickHandler: (e) ->
  newCard = ​new​ window.Card({}, {parse: true})
  allCards.add(newCard)
  newCard.save().then =>
  @model.get(​'cards'​).add(newCard)
  @model.save()
  @render()
 return
 return

And that does it! With those alterations, our Backbone application can now read from and write to our Node API. Open up http://localhost:8520 in your browser and behold the glory of a genuine web application!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.91.47