19 March 2012
Basic understanding of JavaScript. If you haven’t already read Part 1: Getting started and Part 2: CRUD, do so before proceeding with this article.
Sample files:
All
In Part 1: Getting started, we set up the basic infrastructure for the Wine Cellar application. In Part 2: CRUD, we added the ability to create, update, and delete (CRUD) wines.
There are a few remaining issues in the application. They are all related to “deep linking.” The application needs the capability to continuously keep its URL in sync with its current state. This allows you and your users to grab the URL from the address bar at any point in time during the course of the application and re-use or share it to go back to the exact same state.
In Part 3, we add support for deep linking in the Wine Cellar application.
Run the application for Part 3. The create/update/delete features are disabled in this online version.
The problem:
You will see get an empty screen with no data. If you look at a debug console (for example, in Chrome’s Developer Tools), you’ll see the following message:
167 Uncaught TypeError: Cannot call method 'get' of undefined
Let’s take a look at the code, as follows:
The problem is on line 20. We wrote the code assuming that a wine collection (this.wineList) already exists, and we are trying to “get” a specific item from that list. That works well when a user starts the application with the default (“”) route. But this.wineList won’t exist if a user starts the application with the “wines/:id” route. There are different ways to address the issue, as described in the following options.
We could modify the wineDetails function to fetch the requested item directly.
That takes care of loading the wine details in the form, but the wine list remains empty when a user starts the application with “wines/:id” route.
We could add the following line of code to load the list if it doesn’t exist.
But now the wine model that is part of the collection and the wine model fetched separately are two different objects, which means that data binding and View synchronization will not work as expected.
We could check whether the collection exists in the wineDetails function. If it does, we simply “get” the requested item and render it as we did before. If it doesn’t, we store the requested id in a variable, and then invoke the existing list() function to populate the list. We then modify the list() function. When we get the list from the server (on success), we check if there was a requested id. If there was, we invoke the wineDetails function to render the corresponding item.
Run the application for Part 3. The create/update/delete features are disabled in this online version.
The problem:
You can easily fix this issue by using the router’s navigate function to change the URL. The second argument (false), indicates that we actually don’t want to “execute” that route, we simply want to change the URL.
Run the application for Part 3. The create/update/delete features are disabled in this online version.
The problem:
To fix the problem in this case, add a new “route”:
The router’s newWine method is as follows:
Change the HeaderView newWine() method as follows:
Download the final version of the code on GitHub. Additionally, I posted a “Postface” to this series with some lessons learned and an improved version of the app. Make sure you read about it in my blog post: Backbone.js: Lessons learned and improved sample application.
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.