What do you want to learn?
Skip to main content
by Liam McLennan
Resume CourseBookmarkAdd to Channel
Table of contents
What Is Backbone.js?
Single Page Applications
SPAs or Single Page Applications are becoming the standard for high quality web applications. A single page application is a web application that loads all of its resources as a single page load and then executes in a single web page. Client-side scripting in Ajax are used to provide user interaction instead of regenerating pages set aside. This technique is used to provide an improved user experience until they bring faster and more advanced user interaction. SPAs are the results of an evolutionary process. In the beginning, the web was a connected set of static pages. After that came server-side applications. Each user action resulted in an independent request to the server-side application which would respond with a completely regenerated page. In this model, the user is constantly interrupted by network latency and page redraws. Actual performance suffers because the redundant work being done to constantly regenerate the page and retransmitted over the network. Because entirely server-side applications unlimited and boring, web developers begin to enhance them using client-side scripting and Ajax. This is the hybrid model of web development. And finally, SPAs develop us by completely moving the use interphase, logic and generations to the client. The responsibility of the server is reduced to the initial serving of the SPA, providing data services and any other activities that cannot be performed on the client. User interactions result in immediate feedback just like a desktop application. And much of the server communication can be done asynchronously without the user having to wait and being interrupted in their task. When a person uses your application, they are trying to perform a task or achieve a goal, repeatedly forcing right time into the process as server-side web applications do breaks the users flow and delivers a substandard user experience. The hybrid model is popular at the moment because it promises familiarity as well as an improved user experience. However, it is a fraud and impure architecture. When developing a hybrid application, it is never clear where responsibilities belong. It can feel messy and random. Gmail is possibly the most famous single page application. Gmail users can search, scan, read, send and delete their email without a single page reload. Facebook, like most SPAs, is not strictly a single page. SPA is a concept, not a strict definition. It often makes sense if your application to consist of a set of SPAs. Twitter.com is an SPA that makes use of model dialogs to squeeze more information into the user interphase. Trello is a fancy to do this application. Let's have a quick play with Trello so you can see what an SPA is like. This is Trello. Trello is a web app used to manage list of anything. Here I have three lists, basics, intermediate, and advanced. Each list has a number of cards. I can open a card by clicking on it to see more detail. I can change a text field by selecting it and editing it in place. I can add new cards. I can reorder cards within a list, and I can move card form list to another. For any given card, I can add a checklist and then add things to the checklist. ( Pause ) And check those off as I'm done. I can give a card some label, choose a color for the cards label, give the label (inaudible), I can add an entirely new list to this board and reorder list. If I'm working in team situation as somebody else is using the same trial board at the same time. If my team member adds a card-- ( Pause ) It's automatically added to my Trello board as well. So this some same real time capabilities, they are all sort of soft real time. And if they were to archive that card, watch it disappear. So the two boards in different browser Windows is dancing. Trello is an excellent example of what can be done with client-side web applications and the single page applications if you prefer that term. It's also a great example of a Backbone application. And I think a very good case study of why the style of application can deliver a advanced either experience. It's not all good news. SPA is introduced some unique challenges. SPA is not new but it fair to say that the technology is immature compared to the server-side web frameworks is a lack of tooling and experience developers. When Google is part as an SPA, it receives an empty page because the content has not been generated yet. If search engine is important for your application, then you'll have to do some extra work to make your content visible to search engines. This will be covered later when discussion Routing. Running is a substantial portion or your application client-side increases your dependence on the user's browser. And some browsers are a lot better than some others or becoming this means that you may choose not to support some older browsers. Also, you want to follow standards for HTML, CSS and JavaScirpt and you'll need to thoroughly test in multiple browsers.
Why Do We Need Backbone.js?
Creating client-side applications without using a framework or library is hard. Often, it degenerates into a tangled mess of nested go backs and event hand list. Hr need help to develop coherent, readable, structured, testable, and maintainable client-side applications. Backbone contains tools and codified knowledge that minimize the difficulties. Backbone provides a set of tools for introducing structure into client-side applications. Models represent the data required by our application. They hold your applications data and raise events when data changes. Collections, group models, they also for the events from the models they contain as well as events that they earn. The arrow here represents the dependencies. So, collections depend on models. Backbone connects the various components indirectly using events. Events travel in the opposite direction to the dependency shown. Views handle event from models and collections. They are responsible for rendering any mark up. Views are the only backbone component that typically interacts with the document object model. So views can also handle events from the DOM. Backbone routers are used to simulate page changes and to provide support for page history and bookmarking. What I've shown here are not rules, but more like a starting point. In particular, a router may optionally depend on models or collections. What's shown in the diagram is the simplest to configuration. Backbone is a lose collection of helpful components. You can use them anyway that make sense to you. Backbone has two required dependencies. Underscore.js is a library that provides functional programing support for JavaScirpt. Backbone provides many functions from Underscore.js as methods on Backbone collections. Even when not using Backbone, Underscore is a tremendously useful library. For dealing with the DOM and for making Ajax request, Backbone requires jQuery or zepto. Zepto is a lightweight alterative to jQuery with a largely compatible API. Zepto is popular for mobile projects, but usually don't have to support very many browsers.
A Minimal Backbone.js Environment
A Backbone Example
Web applications are becoming more interactive. We want to make them faster and more like this to web applications. But developing web applications with client-side state is hard, and the tools are relatively immature. We need some help. Backbone is a library that helps organize client-side applications. It's not framework and it's not MVC.
The previous module of this course introduced Backbone JS, explained why it is helpful for the modern web application developer and provided a quick demonstration of some of its features. Now, it's time to begin examining Backbone in detail and the best place to begin is with models. Backbone is a collection of loosely components so it is certainly possible to build an application with Backbone and not use Backbone models, but you probably won't and I'll explain why. I'll demonstrate how to define your own model types, how to instantiate new model objects, how to get and set model properties, and how to use model events. Model identity has complexity because models are often synced to a server. The model has identity in your client application and the model has identity on the server. Backbone provides some support to help maintain the identity of model objects throughout their life cycle. Backbone models can declare default property values and finally, we'll look at Backbone support for model validation.
The Purpose of Models
Defining New Model Types
When you have many model objects, you need a way to tell one from another. Backbone gives each model object an id property. The id property represents the model's persistent identity. It is undefined until the model has been saved. When the model is saved, the id property is set to the server's identifier for the model object. The cid property is a temporary indentifier used until a model is assigned its id property. Once a model is saved and acquires an id property, the cid is no longer required. Model objects have an eased new method that can be used to test if the model has been saved to the server and has an id property. Here, I've created a brand new Backbone Model called ford. If we take a look, at its id property-- so this is the id property of the newly created model object. The id is undefined and that's because that ford object hasn't been persist to the server yet, so it hasn't been given its id. But if we take a look at its cid property, the cid is still zero. C id ZID is flood as soon as the model object is created. And finally, is we call the isNew method, so isNew will return a boolean indicating if this model object has been saved to the server yet. It tells us that the ford object is new, is new and is true meaning that it hasn't been saved to the server yet.
When you define a new backbone model type, you have the opportunity to just specify default attributes. The default's property specifies default values to attributes that are not set in the constructor. Specifying defaults has the additional benefit of documenting a model type properties. In this example, I define default values for the color and type attributes of the vehicle type. When I create an instance of the vehicle type, the color and the type attributes are automatically set to the default values. This is the vehicle type definition from the slides. As usual, we extend the Backbone.Model, but this time, we're providing a default's property. And the default's property contains two properties, color with the value of white and type with the value of car. When I proceed to create a new vehicle object, I'm nit initializing any attributes in the constructor. If I then log the values of the color attribute and also the type attribute, we expect that they'll have the default values already set. And so the value's output, the white and car which are the default attribute values.
Backbone exposes model validity through two methods, validate and isValid. Validate test the validity of the model and returns any errors found. IsValid returns a boolean indicating if the model is currently valid according to the validate method. It's possible for a model to become invalid because set can be called in a way that does not trigger validation. Validate is called by Backbone prior to performing set or save operations. Set is the function we used earlier to set the value of model attributes. Save is a function that is used to persist the model. If the model is found to be invalid, the operation is canceled and an error event is triggered on the model. To add validation to a Backbone model we've run implementation of the validate method when we define a model type. The validate method has an argument containing the model's attributes. I'll create an object of the vehicle type. In order to detect the validation problems, I need to register an event handler for the error events. The car object will raise an error event whenever a validation problem is found. The call back that handles error events receives a reference to the model that raise the error and the error itself. So in this handler, I'm just going to log the error. At t this point, I can set some values on my car object. So when the foo attribute is set to the value bar, that's going to trigger my validate method which currently has no implementation, so there would not be any error raised at this point. We'll run it now just to check, and so it's fine, there's been no error raised. Okay, so the next step is to implement my validation. For this vehicle, I would like to validate the vehicle's color. I'll start by defining what is a valid color. So I'll creator an array of valid colors, white, red, blue, and yellow. If my vehicle's color attribute is one of these four values, then I'll consider that to be valid, otherwise the color attribute is invalid. So next, I'll define a function, it's going to check if my model object has a valid color, call it color is colorIsValid to function. Its arguments are the attributes. The first thing I'm going to check is if my model even has a color attribute. So what this will do is if my model doesn't have a color attribute, then I'm just going to return true. Know that color attribute defined is considered a valid value. Here. I'm using the underscore library and with underscore, I'm going to wrap my array of valid colors and use the include method to search for the model's color. So this is going to return true if the valid color's array includes the current color attribute of my model. So having defined my color as valid function, I can now use it. If my models color attribute is invalid, then I'm going to return an error message. Color must be one of in a list of what my valid colors are. So now, if I attempt to set an invalid color, and first I will attempt to set a valid color, so blue is a valid color. Set the color attribute to blue, run that example. I get no output because there's no error. However, if I now attempt to set the color to mauve which is not in my set of valid colors. I would expect that my color validation function is going to fail and it should return the error message. So that's triggered the model's error event calling through my event handler which has logged the error message, colors must be one of white, red, blue, or yellow. If I then were to check the current contents of the color attribute, log that to the console. The color attribute is currently undefined because setting the color to mauve failed, so that operation was canceled, the color attribute is still on set at this point. If I were to set it back to red, that operation will succeed. So then when we try to read the color, we'll get red. One slot variation is if we choose, when setting an attribute value or an array of attributes, we can override the implementation of the error event handler. We can provide a specific error event handler for that set operation. I'll show you what I mean. I'll use the set method and I'll set the color attribute to turquoise which will cause an invalid value according to our validate function. But now, I'll provide a second argument to the set method which is an object containing an error property which is function. So what I've done here is provide a custom error handler for this particular set operation. I will see in that, I'm just going to (inaudible) the error. So instead of the usual error handler which logs the error to the console, this time I'm going to display the error in an alert. So when we run that, turquoise is not a valid color according to our validate function, so the error handler is triggered and the message is displayed in an alert.
save, fetch and destroy
Models have save, fetch, and destroy methods for synchronizing with the server. Save performs insert and update operations depending upon the state of the model. If the model is new and has never been saved to the server before, then save will perform an insert on the server. If the model is an existing model that has previously been inserted, then save will perform an update. The fetch method updates the model with the current server-side state. And the destroy method deletes the model from the server. The details of server integration will be covered in the later module of this course. ( Pause )
Views of the interface in both directions between your HTML document and your Backbone models end collections. For most applications, views will form the majority of your Backbone js code. (Silence) The first thing we need to cover is the high level description of what views are and how they're used. Then we'll move on to defining custom view types and instantiating instances of views. (Silence) Views provide a number of useful properties so we'll investigate each of those. Most views need to generate or modify some part of a HTML document and that is the random methods responsibility. (Silence) Views are often backed by a model. We'll have a look at how that's done. Views receive events from models and from the HTML document.
Backbone dot view and your types that extend it are used to bind models to the document. The Backbone documentation says the general idea is to organize your interface into logical views backed by models each of which can be updated independently when the model changes without having to redraw the page. Views often handle model change events as well as events raised from the DOM. In the diagram, the arrows between boxes show the direction of the dependencies. Views depend on models. Models trigger events that the view can handle. Views depend on the DOM and the DOM can raise events that the view can handle. New view types are defined by extending Backbone.view. As with models, you can create an inheritance hierarchy if you need to. All views have an associated DOM element at all times available in the .el property. The element is either passed to the view's constructor or it is created by the view. Some views create new DOM elements. Using the tag name, ID, class name, and attributes, Backbone will create a new DOM element for this view when the view is instantiated. Tag name is the name of the HTML element that will be created. ID is the elements ID. Class name is the elements class attribute. And attributes is a collection of other attributes to be added to the element. Here I'm defining a new backbone view type called V. The tag name is li so this view is going to represent elistodum (phonetic). Elistodum is going to have an ID of thing. It is going to have a CSS class of active. And it's going to have an attribute called data-value with a value 1, 2, 3, 4, 5. I declare a new instance of the view type the normal way by calling its constructor. And then I can use J query, select the document's body and prepend the view's element. When I run this code, you'll see in the HTML view over here a list item has appeared. And if we look at the markup that's been created, it's a li element. It has attributes of a data value, ID and class. Sometimes if you use an attached to a DOM element that already exists, the best way to do this is to pass the element to the view's constructor. Here's an example I've prepared earlier. I've declared some markup. I have a div with the ID test and the content -- test content. And then the code for this example declares a new view called V. It instantiates an instance of that view passing to the constructor an element selector of hash test so that's going to select the HTML element with the ID of test which matches the div that we've added to the page. Once the views been created, we can then access the .el property and use the CSS method to set the background color to cornflower blue and the result as you can see is that the background color of my div has been set to cornflower blue. So this is an example of attaching a Backbone view to a DOM element that was already a part of the document.
Views like models are created by calling their constructor function with the new operator. To create a view with no special behavior, we can instantiate an instance of Backbone.view. To define specific behavior for a view, create a new view type by extending Backbone.view. You can then create new instances of your newly defined type. Often you will pass a model to the view constructor. The model contains the data that is used to render the view. (Silence) There are a set of properties that if supplied to the view's constructor, will be copied to the view object. These properties are model, collection, el, ID, class name, tag name, and attributes. To demonstrate instantiating a Backbone view, I'm going to start by defining a new Backbone model. Now my model is an instance of the Backbone.model type so I haven't bothered to define my own model type. I'm just using the default Backbone type. And then I'm setting up a property called content to a string value. Having done that I can now create a new view. And again, I'm just going to use the view type that comes with Backbone. And when I create my new view, I'm going to provide a model object which is the model that I previously created and I'll set class name as well. Finally, using J query, select the document body and prepend the view's element. Let me run that. ( Silence ) And inspecting the rendered markup, we find there's a new div with the class model object. So that is the view object that we've created and added to the document.
The el Property
Next we're going to go through some of the properties of Backbone views beginning with el. El is a very important property that refers to the view's DOM element. Every view maps to exactly one DOM element that may or may not have been added to the document. (Silence) In this example, I create a new view passing a selector that will select the document's body. The selector can be anything that would be a valid J query selector. The element property of the view then refers to the document's body. Let's try that out. (Silence) Here I have the J is fiddled with -- I've added a little bit of custom markup. The same div that we've seen before with the ID of test. In the java script code, I'm instantiating a new backbone view and passing in a selector for the body of the document. And then logging the content of the view's element property or el property. If we run that and have a look in the console, we can see that the views el property is the content of the document's body. Another important property on the view is dollar el. Dollar el is a J query object containing the el property. It's therefore a J query object wrapping the view's DOM elements. Dollar el is cached to avoid repeatedly creating the J query object. This example is similar to the last one. The view is created with an el selector for the document's body. Once created, the view's dollar el property contains a J query object containing the document body. (Silence) This example is very similar to the last one. We have a test div. We've created a new view. We pass the body selector for the element, the views element. And then this time, we're logging the dollar el property of the view. So instead of that being the DOM element for the document's body, it's going to be a J query wrapper containing the DOM element of the document body. If we run that example. Go to the console. And see again, very similar to the output from the last example except that you see that there is actually an array containing one item. That's because it's a J query wrapper. Dot dollar is a version of the J query function, scoped to the current view. Using this dot dollar means that your J query selectors don't have to be unique for the whole page, just for that view. Using the dot dollar property is equivalent to calling the find method on the dollar el property.
Render is the function that renders the view's element usually based on the view's model data. The default implementation doesn't do anything. When you define your own view type, you should implement a render method that generates the markup you require. By convention render methods return this. This patent makes it easy to chain method calls. Generating markup for models and binding views to the models change events is the core of Backbone js. To set a view's model, pass the model to the view's constructor. (Silence) Often as in this example, an event handler is attached to the models change event and the view is rendered by the event handler. One model can provide the data for many views. If anything causes that model's attributes to change, all of the bound views are automatically updated. Let's think about a view that automatically refreshes when it's model's data changes. I'm going to define this view and call it refreshing view. (Silence) As usual, we extend from Backbone.view. I'm going to use the initialize method to set up the binding to the model. My views model can be accessed by looking at the model property, this dot model. And to bind to a change event, I use the on method. The name of the event to bind to and then the handler function. And within the event handler for the models change event, I simply want to call this dot render to render the view. I also need to pass the view object as an argument to the on method. Now what that does is it ensures that when my event handler function is called it sets the context for the event handler. Okay. So now I'm set up such that any changes to the views model will cause the view to be re-rendered. But I still haven't defined a render method so currently I have the default no-off render method. So the next step is to specify what it means to render this view. So I create a render function. Within that render function, I access my J query wrapper around the view's element. I want to replace the element's content so I use the HTML method from J query. I'm going to replace it with the model's text property. So when I pass a model to this view's constructor, I have to make sure that it has a text property. So that's it for the definition of our refreshing view. The next thing I'm going to do is create a new model. (Silence) And as I said before I have to make sure the model has an attribute called text. I'm going to set that to the current date. I can now create a view object so it's going to be a new instance of my refreshing view. I'm going to specify the model object to use to be the model that I just created. And I'm going to specify the element to be the document's body. And then render the view. (Silence) I've created a custom view and a new model. And my view is configured so that it will re-render itself when it detects a change to the model object. At this point, I can run this. And you see, it replaces the document's body with a string indicating the current time. To prove that this works and that it will in fact track changes to the model, I'm going to set up a timer using the set interval method. When the timer fires, I'm going to change the text attribute of the model to whatever the date happens to be at that time. And I want this to trigger every one second, one thousand milliseconds. I create a view. I apply a model, render the view. And then every second after that, modify the view's text property. When the view's text property is changed, it's going to trigger a change event. The view will handle that change event and re-render the document's body. So what I expect to see when I run this example is that the date printed in the document's body will update once every second (Silence) like so. So you can see the seconds are incrementing. ( Silence )
Occasionally, you will need a lightweight technique for generating DOM elements without using templates. You could manually build a string and have J query generate a DOM element for you or you could add a bit of structure using Backbone's make method. Adding a bit of structure is what Backbone is all about. The three arguments to the make method are the type of the element to create the attributes to set on the element, and the value of the element. In this example, the type of the element is h3. The attributes are a class attribute with the value, not very important. And the value is preliminary version. The comment at the bottom is the element that would be created. This is the example from the slides, h3 not very important class, and the value preliminary version. If I run this example, it is going to dump that element to the console and you can see it creates the HTML DOM element that we would expect. ( Silence ) Remove is a method that removes the view's element from the DOM. It's equivalent to calling J query's remove method on the Dollar el property. Calling a remove when a view is no longer required is an important first step towards preventing memory leaks. To demonstrate the view's remove method, let's start by defining a Backbone model. This model represents the data that we're going to render into a header and it contains a single attribute content with the value historical context. So the next thing we need is a header view to render a header. And it's a custom view extending from Backbone.view. It's going to render as a p tag also known as paragraph and in the render function, you're going to set the content of the view's element (Silence) to the model's content attribute. (Silence) Now to clear the instance of the header view (Silence) and provide my header model as data for the view. And with J query, I'll render the view and add it to the document body. Call the render function, access the element. If I run this code, it's going to create a view based upon my model and add it to the document. There it is. If we have a look at the markup, it's created a paragraph tag with the content, historical context. It's exactly what we were trying to do. Okay so now, I can use the view's remove method. If I run the code again, it's going to create that paragraph, add it into the document, and then immediately remove it. Like that so that the paragraph's gone. The remove function is just a convenient way to remove the view's element from the document.
Backbone views have a nice declarative syntax for specifying DOM movement handlers. It's very important to understand that Backbone views should be self-contained. Therefore, they only handle events that occur within their own elements. In this example, I'm declaring that the handleClick function should handleClick events on the elements within this view that match the selector dot clickable. Events is an object or a hash where the key is of the form event name, then a space. Then a CSS selector. So we're going to handle that event that occurs on those elements and the value side of each property is the name of the event handler function. If you wish and if things are simple enough, you can also just directly put the function in that position. Otherwise, you just declared the function somewhere else on the view. The previous declarative event declaration is equivalent to this imperative J query code. So we're doing the same thing within the current view. You use J query to select the elements that match the dot clickable CSS selector. And attach a handler for click events and the handler function is handleClick. (Silence) To demonstrate how Backbone views deal with DOM events, I'm going to create a new view called form view. And as in the previous example, we provide a property called events which is an object. The key on an event name followed by a space and then a CSS selector. And the value is the name of the event handler function. So let's start with that. So configure one event handler. I'll add a render method so that our view has some markup. I'm simply going to render a very simple HTML string. (Silence) So that render function is simply going to generate two text boxes. The first one has a placeholder containing the word clickable and it also has the CSS class clickable. The second one is just a plain vanilla text box. A previously configured event handlers to call a function called handleClick. So now I have to define that function on the view. And within the handleClick function, I'm just going to log a message with the name of the event handler. That's enough code now that I can create a new instance of that form view. And using J query, select the document body and append the result of rendering the form view. If I run that now, gets some output, you can see here it's rendered my two text boxes. The first one has a clickable placeholder and it has the CSS class clickable. The second one is just a vanilla text field. My clickable text box has an event handler configured such that when the text box is clicked, it logs a message called handleClick. As you can see in the console if I click that, every time I click it, it logs a message handleClick. If I wanted to add a second event handler, I add another entry to my events object. This time I'm going to handle the change event. I'm not going to specify the CSS selector so that's going to apply to everything. And I'll declare the event handling function in line just to show that you can do that if you want. Although if there's any sort of complexity within the event handler, this tends to be more difficult to read but for very simple cases I think it's okay. Once again, I think I'll just log a message, handle change so we can tell the two events apart. Render the page again. Once again, I still have the click handle on in this clickable text box. Every time I click in there, it writes the message handleClick. If I put some text in the text box and then move the focus away, that raises a change event and we get the handle change message logged. And the same is true of the second text box. Enter some text in there. Move the focus away and the change events fired again and the event handler runs and logs the message, handle change.
Guidelines and Summary
As I mentioned before, it's important that views be self-contained. If you don't, your program can become difficult to manage and testing will be a nightmare. Do not attach to existing elements other than the elements passed to the view's constructor. And above all, do not access DOM elements that are not part of the view. If your view is set up to refresh itself when its models is changed, make sure that the view's element is supplied to the constructor not generated by the view. If you don't do this then the view will regenerate its element when it detects a change but the element will never be added to the document so the update won't be visible. Views are the components responsible for mapping between models and the user interface. They render model's attributes to markup. They handle DOM events and they handle model and collection events.
Templating is a core dependency for client-side applications. Nearly all client-side applications all require a templating library and the one you choose will become an important part of your project. Backbone depends upon underscore. So using underscore templates is an easy way to get templating support without having to take any additional dependencies. Handlebars supports semantic templates meaning templates that don't include code and it has a powerful pre-compilation tool. Pre-compilation is essential for any real world application. Either use something like handlebars or write your own script to find all your templates and pre-compile them for you.
Client-side routes are a way to change the browser URL and to trigger a function when the browser URL changes. Backbone routing includes parsing of the URL to extract route tokens and matching the URL to the correct route handler. Client-side routes are used very differently to server-side MVC routes. In particular, it's not necessary for every user action to trigger routing. Use routing only when you need to substantially change the application context, to generate a bookmarkable URL or to generate browser history that can be navigated backwards and forwards. Each route results in two different scenarios that must be accounted for. We'll look at those next. Routes can be triggered in two different ways. The first is when the browser initiates the request because the user enters an address in the address bar, refreshes the browser or clicks a hard link. In this case, the request begins at the browser. The browser initiates a request to the server. The server will process the request like any other and return a response. When the response has been loaded in the browser, the Backbone router will try to match it to a route. If a match is found, then that route's function will be called. That's the process that occurs when the request is caused by the user's interaction with the browser. The other thing that can trigger a route is a client initiated request. When your client-side application undergoes a significant state transition, such as changing from one page to another, you can tell the router to update the URL and optionally trigger routing. Doing so does not trigger a request to the server. This time the progression is: Backbone updates the browser URL and initiates routing. The Backbone router tries to match the URL to a route. If a match is found that route's function is called. Much of the complexity in dealing with Backbone routes is in accounting for these two different routing scenarios. Don't use routes unless you want to change the browser URL to provide an addressable state or a potential bookmark.
A Document Router Demo
PushState and Hash Fragments
Search Engine Indexability
There's only one thing better than the backbone model and that's a collection of backbone models. Collections group related models together at a convenient way to persist them and provide a set of helpful functions for dealing with sets of models. Just like models, a collection can be used as the basis for a view and binding a collection change event to a view's render function will automatically keep them in sync. When there is a set of models of the same type that you want to group together, use a collection. Collections have sorting capability that not only allows you to sort a collection but also to keep the collections sorted as models are added and removed. When working with collections, you are definitely going to want to move models in and out of the collection. There are many different ways to access models in a collection, the most basic being array-like random access. Backbone collections have 28 iterator methods. The things like funding a model, reducing a list, mapping a list, sorting, grouping, and shuffling. Like models, backbone in collections published a number of events. There are events from model added, model removed, model changed, model destroyed, collection synchronized, collection reset and validation error.
A backbone JS collection is a container for storing a set of related models. Collections, like models, have a URL property and it can be used to retrieve a set of models from the server or to create a new model on the server. Collections group related models. For example, you might divide your models into old and new categories and have a collection for each. Collection is an array-like object. Like an array, it has a length property that tells you how many elements it contains. Also, like an array, it can be indexed although the syntax is different to an array. You can't index a collection using square brackets. You must use the 'at' method. A new collection archive can be created by calling new Backbone.Collection. The collection can be populated by passing an array to its constructor. ( Pause ) Having created a new collection, we can now log its length property. ( Pause ) The length is two because I've added two objects to the collection. And I can use the 'at' method to index into the collection and log the first item in the collection. ( Pause ) The first item is a backbone model containing a property called name with the value 'thing', which is the first object that I added to the collection.
Defining New Collection Types
By now, you will have noticed the pattern that backbone uses for defining new types. As with models and views, to create a new collection type we call the extend method on the backbone base type, in this case, Backbone.Collection. It's common to specify the type of the models that the collection will hold. In the example shown here, I create a new collection type called vehicles by extending Backbone.Collection. I declare that the models contained within this collection will be of type of vehicle. Let's start by defining a new model type called vehicle. And now I can create a collection type called vehicles which will hold a set of vehicle models. ( Pause ) And now I'll instantiate an instance of the vehicle's collection and provide some vehicle objects to the constructor. ( Pause ) I can log the collections length to inspect how many elements it contains, currently two. And I can also log the result of serializing one of the models contained within the collection. Access an element within the collection by using the 'at' method. ( Pause ) So that logs the serialization of the first element in the collection or I could serialize the entire collection. ( Pause ) Like models, collection types can have class properties. These are properties available directly on the type rather than on instances created from that type. To add class properties to a collection type, pass them as the second argument to extend. ( Pause ) Here we have our previous example. It starts by declaring a new backbone model type called vehicle and then declaring a new backbone collection type called vehicles which will hold models of that vehicle. To add a class property to the vehicles type, I need to pass a second argument to the extend method. ( Pause ) The second argument is an object and each property of these objects becomes a class property of the collection type. So I'm going to add a property called oneVehicle and this is going to be a function, that when this function is called, it will return a new vehicle model. ( Pause ) Now I can use that class property without creating an instance of my collection type. I can call it directly on the type itself. So we can see what that does. I'll log the result to the console and run the example. So the oneVehicle function has returned the vehicle model as defined.
Collections are sorted. By default, the items are sorted by the ordering which they were inserted or they can be sorted by a comparator function. The comparator is a function that knows how to order your models. If you define a comparator, then the items in your collection will always be correctly sorted according to the comparator. In this example, models in the vehicles collection will be sorted by their sequence attribute. ( Pause ) This is a standard vehicle model and vehicles collection. To make these collections sorted, I add a comparator function. ( Pause ) This is a function that has a single argument which is a model of the type that the collection holds and it returns some value based on that model and backbone will sort the collection b y those values. So in this case, my comparator function returns the sequence attribute of the vehicle. The vehicles in the vehicles collection will be sorted by their sequence. That's the first type of comparator function with an input which is a single model of type contained in the collection and an output which is the value to sort by. Now if I instantiate a collection of vehicles and provide some data-- ( Pause ) -- and finally, log the contents of the collection. ( Pause ) What we see is that even though the vehicles were added, red first and then blue, because we're sorting by sequence the output has reversed the order and the blue vehicle is in the first position and the red vehicle is in the second position. This is the first type of comparator function. Takes a single argument which is an object of the type that the collection holds and it returns some value to sort by. There is a second type of comparator function that you can use. The second type takes two arguments which is two objects of the same type that the collection holds. The function should return minus one if the arguments are already in the correct order. That is vehicle1 is considered to be less than vehicle2. It should return 0 if they compare the same and it should return positive 1 if the order needs to be reversed. That is if vehicles2 is considered to be less than vehicles1. For this example, I can implement by sequence comparison like so. ( Pause ) Now when I run this example, once again, the order of my collection has been reversed so that now they're ordered by their sequence number. ( Pause )
add() and remove()
'At' is a function that provides array-like random access to models in the collection. Like arrays, collection indexes are zero-based. That is the index of the element in the first position is zero. Therefore, the index of the last element in the collection is the length of the collection minus 1. Let's begin with a new collection object containing three model objects. ( Pause ) Using the collections 'at' method, I can retrieve any model object in the first position in the collection. The first model is Fred and that's the model that's returned. If I wanted to get the last model in the collection, again, I can use the 'at' method and retrieve the model at position length minus 1. ( Pause ) The last model in the collection is Dave.
get() and getByCid()
Get and getByCid are two functions for retrieving a model from the collection by its id and Cid properties respectively. Get retrieves by the model's id property. getByCid retrieves by the model's Cid property which is necessary if the model has not been saved yet because until the model is saved, it will not have an id property. Cid is an abbreviation for client identifier. You may remember from the models module that all models have a unique Cid assigned to them when they are created. They don't receive an id property until they are saved to the server. ( Pause ) I'll start with a standard collection containing a single model. I mentioned that all models have a Cid property from the moment that they are created. If I inspect the single model in my collection at the moment, it has the Cid c0, which is the first Cid that's assigned. Now that I know the Cid of my model, I can use that to retrieve the model from the collection using the getByCid method. ( Pause ) getByCid given the model's Cid, c0, returns that model. If I change that Cid to something else that doesn't exist, I get undefined.
Working with Collections
We can detect when a model is added to or removed from a backbone collection by listening for the add and remove events. As always with backbone, event handlers are attached by using the 'on' function. When an add or remove event is triggered, the handler is passed the model being added or removed and the collection. To demonstrate the collection's add and remove event handlers, I start with an empty standard backbone collection. The next step is to create a backbone model. And now I'm going to configure the event handlers for the collection using the 'on' method. First stop is the 'add' event. When a model is added to the collection, I want to log a message to the console. And the content to the message will be the serialized model and the word 'added'. ( Pause ) If I then use the add method to add the model that I've defined to the collection, I expect it to trigger the 'add' event and therefore invoke my 'add' event handler. So in the 'add' event handler, it's logged the serialized model and told me that it's been added. Now I can add a second event handler. Again, using 'on', and this time I'm going to listen for the remove event. And this event is fired whenever a model object is moved form the collection. When the models removed, I want to log. Again, this serialized model and this time the word removed. ( Pause ) And then I'll use the remove method to remove my model from the collection. So this example, I know when I run it, it creates a collection, it creates a model, adds a model to the collection and triggering the 'add' event and the 'add' event handler and then removes the model from the collection, triggering the 'remove' event and the 'remove' event handler. ( Pause ) So the output is we see the model being added to the collection and then the model gets removed from the collection. Both the 'add' and 'remove' events are firing and being handled. ( Pause ) It would be annoying to have to attach handlers to every model in a collection in order to detect the changes to those models. Fortunately, you don't have to. Collections forward model change events, so the easy way is to listen to change events on the collection. We know the model that triggered the events because it is passed to the handler. ( Pause ) Given an empty backbone collection, I can attach a change event handler. This change event on the collection is going to be fired whenever a change event is fired on any model in the collection. Within my handler, I want to log the model that was changed and a string telling me that it was changed. Now if I create a new backbone model-- ( Pause ) -- and add it to my collection, then I'll set a property on the model. And because that's a change to the model object that's in my collection, I expect the models change even to fire and then subsequently the collections change event to fire and be handled by my event handler. So that's what's happened. The change event on the collection has been handled and I've logged the serialized model. The same thing also works for the attribute change events. I can listen to change events for any specific attribute. So in this case, I'm going to add a handler for changes to the name attribute. ( Pause ) When the event is handled, I'm going to log a message just saying that the name property changed. If I rerun my previous example, when it comes time to setting the age attribute to 57, that's a change to the model, so the collection change event will fire but it's not a change to the name property. So the name changed event handler won't fire. We see the same result as previously. However, if I change this-- so instead of setting an age attribute, we're setting a name attribute. Set the name to Jimmy. Now when the name attribute is set, that's going to fire the collection change event and also the change name event. ( Pause ) So the first event, we see handled is the change name event. Runs the handler and informs me that the name property has been changed. And then the collection change event is also fired. ( Pause )
Collections are handy containers for working with groups of model objects. To define a new collection type, extend Backbone.Collection. By supplying a comparator function for your collection, you can ensure that your collection remains sorted by whatever algorithm you require. Use add and remove to move models in and out of the collection. Use get to get a model from a collection by its id. Use getByCid to get a model by its Cid. Use the iterator functions forEach, map, reduce, find, et cetera to do interesting things with collections. Collections publish events for model added, model removed, collection synchronized and collection reset. In addition, collections forward model events for model change, model destroyed and validation error.
Connecting to a Server
While backbone does not require a server, most people will use one. First to serve their application to the user's browser, and then to synchronize model data changes. Backbone implements the client's side of a simple RESTful protocol for persisting changes to model data. The service side of the protocol is easily implemented using your service side web framework of choice. This module is about how backbone.js transfers model data to and from the server. Same origin policy is a browser security feature that greatly complicates data synchronization. Cross-origin resource sharing also known as CORS is a technology that makes it easy again. There are two collection operations that sync to the server-- create and fetch. Models have three operations that sync to the server-- fetch, save, and destroy. The server has to implement a simple RESTful HTTP API. Backbone.sync is the function responsible for all server communications overrided at the model collection of global level to change the way that model synchronization works. Backbone.localStorage is a simple plug-in that overrides the global Backbone.sync function converting the default service synchronization into local synchronization that saves all data to the browser's local storage.
How Backbone.js uses the Server
Backbone uses RESTful HTTP web request to synchronize data to and from a server. Model data is serialized as JSON for network transmission. There is no rule that the server used by Backbone for persistence must be the same server that originally served the application, although the same origin policy does apply. The same origin policy prevents scripts from accessing resources belonging to another site. Among other things, this means that a backbone application cannot synchronize models to a server other than the server that served the current page. For the purposes of the same origin policy, an origin is defined as the application protocol, usually HTTP or HTTPS, combined with the domain name and port number. This is an example of an origin. Because these two URLs have the same protocol, domain, and port number, the same origin policy considers them the same origin. These two URLs have different port numbers and, therefore, different origins. And these two URLs have different application layer protocols and are, therefore, different origins. Cross-origin resource sharing, usually referred to as CORS, is a technology that allows cross origin request. It is an explicit exception to the same origin policy. To implement cross-origin resource sharing a server must include a set of special headers unit types HTTP responses. CORS is an alternative to JSONP. JSONP is supported in all the browsers while CORS is not. CORS supports all HTTP verbs JSONP is limited to get. All the browsers don't support CORS. Let's have a look at this port matrix. So we can see that CORS is not supported in versions of Internet Explorer less than 10, not supported in Firefox 3. It's supported in all the versions of Chrome and most other browsers.
Backbone's persistence protocol is very similar to other RESTful systems. It maps HTTP verbs to data operations. Data fetching is accomplished by the GET verb. Data creation uses an HTTP POST, updates are done via HTTP PUT, and delete use the HTTP DELETE verb. The only slight specialization is that when a new resource is created, Backbone expects the server to return an ID property that uniquely identifies the new resource on the server. The server can be any RESTful HTTP server technology. Ruby on Rails is a popular choice, but ASAP.Net, Web API, Express, Jingo (phonetic), and all the rest are also perfectly capable. I'm going to throw in a very quick demonstration now that will show a basic model synchronization to a server. Let me say the first thing we need to do is create a model and I'm going to define a new model type called Book, so that I can give it a URL that represents its location on the server. And this URL is the location where it happened to know that there is a Backbone compatible server up and running. Now, I can create a new model from that type. ( Pause ) Let's give it some data. ( Pause ) If I call the models save method, that's going to cause the model to be persisted through the server. That's an asynchronous operation, but I can provide success and error functions to the save method, and one of these will get called when the save operation is completed. Obviously, which one gets called depends on whether the save operation was a success or not. Success is defined as resulting in a HTTP 200 status code. If the server returns any status code other than 200, then backbone considers that an error. In my success and error callbacks I'm going to do a display an alert indicating what the result was, either done or error. And that's all that's required to get a client side backbone application syncing to a server. When I run this example, it alerted done, meaning that the save operation was a success. Now, when we look in the network traffic, we see that when I called the save method, backbone did HTTP POST to the model's URL. And the content of that POST was the serialized version of my model. The server returned a response with the 200 OK status code and that's why I got the success callback. You notice also this access control allow headers in their response. These are the calls headers and that's what allows me to synchronize my model to-- without the loop.com even though my application is currently running jsfiddle.net. So, normally, because those are different domains, there would be an error. This is the body of the response from the server and it simply includes the new ID of my saved model. That was nice and easy. But what would happen if I tried to run the same script in Internet Explorer? This time I got the error callback which indicates to me that most likely this server returned an error status code. The reason that this doesn't work in Internet Explorer is because this version of Internet Explorer, Internet Explorer 9, does not support the CORS technology. So, cross-origin request are not allowed. Therefore, running my app on the jsfiddle.net domain, I'm not allowed to make a request to-- without the loop.com.
I searched for simple backbone server to use for demonstration and development purposes and couldn't find one. So I created a little app called backbone server. It implements all of the backbone synchronization operations. Backbone server is for teaching and testing purposes only. It can be used to synchronize any backbone models without configuration, but it stores the data on memory. So, when backbone server restarts all of these saved data is lost. The alternative to using backbone server and what a real application would have to move to is a specialized API created with ASP.Net MVC with API, ruby on rails, node.js or any of those certified web frameworks. ( Pause ) This is the Backbone server homepage on github. I can get a copy of backbone server by copying its git URL. Open at a console and clone the project. ( Pause ) So git has cloned Backbone server into a directory called backbone server. Before I can start this server, I have to install its dependencies which I can do using the command NPM install. This obviously requires no JS to be installed and NPM to be set up and working properly. ( Pause ) So it's going through and installing all of the dependencies for backbone server and all of the dependencies' dependencies. That's finish now so I can start backbone server by calling node and passing the script file which is rasterver.js. That's it. Backbone server is now running. And by default it runs on port 3002. In my browser if I got to localhost 3002, that's going to connect to backbone server and that just tells me that it's running. Here I've got a new console window. And I can use curl to make a request to backbone server, localhost 3002. Our request, some URL endpoint. This shows the details of the request that I've just made to backbone server and the response return from the server was 404 Not Found, and that's because I requested a URL that doesn't correspond to any saved backbone data. And if I go back to the console where the backbone server is running, there's a message that just saying that there was a request to read the people resource.
Collections have a create method that you can use to instantiate a new model, add it to the collection, and save it to the server. Because this is an insert operation, backbone.js uses an HTTP POST. The new model's attributes are posted to the collection URL. If the server side save operation is successful, the server is expected to return a response with status code 200 which is the HTTP success code, and a body containing adjacent object that has an ID property which uniquely identifies the new model. We saw before that I can make a request to my local instance of backbone server with any made up URL, I think I used people before, and get a response. In this case, it's telling me that it does not have any resources at that URL. The Collection Create Method issues a POST to the backbone server telling it effectively to insert a new model. We can simulate backbone's part in that operation using curl. Here I'm using the option for DOVOS (phonetic) and X. X lets me specify that I want to use the POST HTTP verb and the URL that I'm going to post to is localhost:3002/people. I have to add a header to tell the server the content type, which is application JSON. And then the actual data in the body of the request, this is going to be some JSON. So that's the equivalent of what backbone does when you use the collection.create method or try to save a model for the first time. Curl has issued my request and here is a response from the server. I get a 200 OK so it was a successful request. Again, we see the CORS headers, the content type where the response is also application JSON, and the server has simply returned ID 0. So that's the ID of my newly created server side model. Now, if I make a GET request to that URL one more time, now, that I've saved the model to the server, I get that result back. So the server has returned all of the resources at that URL. At the moment there's just one and it's my model for Bob with ID 0. If I don't want to request the entire collection, I can also append the ID to the end of the URL. This URL represents a single resource instead of the full collection. And so this time it's returned just an object instead of an array. If you look at the backbone server terminal, you can see that it's providing some output of the various requests that are coming in, so very basic logging. Here I have a basic HTML template file. It's got JQuery included, underscore and backbone and a script block. Within the script block it defines a new model type called person and a new collection type called people. I can create an instance of that people collection type and then use the collections create method to simultaneously create a new model, add it to the collection, and save it to the server. And I think this time I'll use my local instance of backbone server of course Okay, now, when I load that page in Chrome, it's going to execute that Create Operation. And if I look in the network traffic in Chrome development tools, see there's a HTTP POST to local host 3002/people. The request payload includes the new model that I asked it to create. The response is 200 OK and it's responded with the ID of the new model. Jumping back to my console, again, I'm going to request the people collection. It returned in array containing three models including the ones that I just saved from Chrome. Collections have one more synchronization method Fetch. Fetch triggers a GET request to the collections URL. The server is expected to return a response with a body containing adjacent string that represents the entire collection. The response data is in array of all the models in the collection. ( Pause ) We've seen how the Collection Create Method works. I can also use the Collection Fetch Method. That's kind of populate my client side collection with all the model data from the server. If I reload my page, see this time, instead of the POST that was triggered by Create, I get a HTTP GET. ( Pause ) The request is to the same URL, but it's a GET instead of a POST, and the response is in array containing all the model objects that the server knows about. And this, of course, is the same result that I get if I use curl to do a GET to that URL.
Models have a fetch method similar to the fetch method on collections. The models fetch method requires the model to have an ID defined so that backbone can tell which model to retrieve. It retrieves just a single model, not the entire collection. ( Pause ) Continuing with my webpage sample, for this particular demonstration I need an instance of the person type. And the person has to have an ID and the ID has to be the ID of a model that exists on the server. I know that I have a person with ID 0. And now by calling person.fetch that's going to cause a GET request to the server. It's going to populate that model with the service side data for the person with ID 0. If I want to have access to that data when the request returns, I can provide a success callback which I could use to log the result. Now, jump back into Chrome. I reload the page once again. This time I get an error. But let that run through. It's saying that a URL property or function must be specified. I go back to the code. Here's my definition of a person type. Here is where I create the instance of the person and then call fetch. No way in any of that do I instruct backbone on what the service side location is for that model. So I have a couple of options. One is I can provide a URL property for the person type. Possibly the easiest thing I can do and arguably more common is add my new person model to the people collection. And once the person model is in the collection, the person model is able to derive its URL based on the collections URL. Now, when I run it again, it succeeds and my success callback logs the result from the server. If I look in the network traffic, we see a GET. This time the GET is to a slightly different URL. It's the collections URL with the model's ID appended to the end. It's 200 OK so success on the server side and the data that's returned is the JSON serialization of that model objects that are requested. Models have a save method that persist the current state of the model to the server. If the model has never been saved before, then backbone will issue an HTTP POST to create a new model. If the model has been saved before, then backbone will issue an HTTP PUT to update the model. When backbone creates a new model on the server, it uses an HTTP POST. The POST goes to the collections URL. As always, it needs the JSON content type and some JSON data. JSON data is going to be the JSON representation of the person model. So I'll create a new person called Robert. He's 24. So curl has a done a POST to the /people URL. The server has returned a HTTP 200 OK, and the identifier of the new model object. If we request the full content of the people collection now, there's the new model that I just created. Now, if Robert has a birthday and we want to update that model in the server, it's very similar to creating a new model except that we change the HTTP web to PUT and change the URL to the models URL instead of the collections URL. The Robert model has an ID of 3, so his URL is the collection URL which 3 appended to the end. And I'm just going to change some data. We'll make Robert's age slightly different. Consider request was a PUT to a model's URL, the model with ID of 3. The response 200 OK and there's no content in the body of an update. I'll request the collection again. The Robert model has been updated. I actually made a mistake there and forgot to include the ID in the update, so Backbone server has deleted the ID property from that model. Fortunately, I can put it back. ( Pause ) Saving a new model with backbone is as simple as creating a new model. ( Pause ) And calling the save method. Once again I have to add the model to the collection so the Backbone can work at its URL and reload the page in Chrome. Backbone has made a POST request to the collection URL. The content of that request is the data of my new model. The response is the ID. Now, that I have a saved model, I'm going to fetch that model from the server. And in the success callback, I'll make it changed to the model. It was 22 before so now it can be 23, and then save that change. Reload in Chrome. Now, because I'm updating an existing saved model, backbone is clever and it knows to-- PUT to the models URL. It sends the full serialized representation of the model including the property that I changed. And the response is simply OK. The Destroy Method deletes a single model from the server and removes the model from its client-side collection. Backbone uses the HTTP DELETE verb for the request to the server. The request issued for a delete uses the DELETE verb and its URL is the URL of a model. So the request here is going to delete the person model with the ID of 1. Here you can see the request. Use the DELETE verb. The URL was the URL of model with the ID of 1. Response is just a plain HTTP 200 OK. You find out query the entire collection. You can see that the model with ID 1 has been destroyed. My backbone example remains much the same. Create a collection, create a person model for person that already exist, so provide an ID that exists on the server. Add the person model to the collection. This time instead of fetching, I want to destroy. Reload that up in Chrome. Here is the request the Backbone issued, uses the DELETE verb. The URL is the URL of the model to delete. And the response is OK.
Backbone.sync is the function that implements backbone's default synchronization behavior. By replacing Backbone.sync you can completely or partially redefine backbone's model persistence. A good example is the Backbone.localStorage plugin, which replaces backbone's default RESTful HTTP persistence with persistence to the browser's local storage. Backbone.sync understands four operations, Create, Read, Update, and Delete If you override Backbone.sync, you must support each of these operations. Backbone.sync can be replaced for a model, a collection, or globally. Backbone.localStorage is a plugin that allows Backbone.js to fetch, save, and destroy without a server. Instead of syncing to a server, Backbone.localStorage syncs to the browser's local storage. This is the same webpage skeleton that I've used in the past including backbone's required dependencies. And I've also included one extra script which is the Backbone.localStorage plugin. To use the local storage plugin to replace Backbone's syncing behavior requires two steps. The first is including the script. The second is to configure our local storage when defining a collection. Here I'm defining a new collection type called People and one of the properties that I post to the extend function is called Local Storage and it's a new instance of this local storage. The rest of the script block instantiates a people collection with a couple of model objects, saves those model objects, and then fetches the model objects. If I open that page in Chrome and go to the network tab and XHR. For normal backbone application I would say several network request here to save the various models and then to fetch them from the server. Because I'm using backbone local storage, there's no network operations involved. The model is being saved in the browser's local storage. If we have a look under the Resources tab and local storage, we can see that it's created these three records, one for each of the models that are saved and one representing the collection. ( Pause )
Backbone.js synchronizes with the server via a simple RESTful protocol. Backbone.sync is the single function that implements Backbone synchronization behavior. It can be partially or completely replaced to implement customs synchronization. Backbone.sync can be customized for a model, a collection, or globally. The same origin policy prevents a Backbone.js application from making request to different origins. You would get errors if your models and collections sync to an origin other than the one that serve the current page. For some modern browsers, you can get around this by using cross-origin resource sharing a.k.a. CORS. Backbone.js default synching behavior maps, create read update, and delete operations to a synchronized RESTful server request. It's easy to implement a custom server, or for testing and discovery purposes you can use Backbone server.
Test runners are simple tools that have two -- sometimes three -- responsibilities. Firstly, they collect and execute tests. They also take care of collecting and reporting the results. Optionally, they often include an assertion library for checking out assumptions of what a program will do and generating failures, when our expectations are not met. There are many test runners available, and which one you choose is largely a personal and stylistic decision. Some of the common ones that you will notice people using are Jasmine, Mocha, and QUnit. This is a Jasmine test. Jasmine tests are organized as specifications grouped into contexts. In this example, the context is 'some context'. And the specification is 'should show some observable behavior'. Each context and specification is defined by a string description and a function implementation. Contexts are often nested inside of other contexts. This is the Jasmine home page. It is a nicely-organized set of documentation that shows the features of Jasmine side-by-side with current examples. If you'd like to get started with Jasmine, reading the documentation is an excellent way to get up and running. This is another example of a Jasmine test skeleton. At the top level, it defines a context, labeled 'some context'. Within that top-level context, it defines another nested context. And within the nested context, there are two specifications. It 'should show some observable behavior', and it 'should show some other behavior'.
Routes and routers are closely tied to the browser environment. It's not easy to test them in isolation. Therefore, my preferred strategy is to keep routers as simple as possible. Defer all real work to some other independently-testable piece. Limit the responsibility of route handlers to defining which part of your application is invoked, when that route is triggered. If you really want to test backbone's implementation of routing, then you need to do a full functional test, through the user interface.
Testing Without a Browser
Liam is a software developer, technologist and product delivery expert. He thinks a lot about how to manage software delivery projects and how to grow high performance teams.
Released5 Sep 2012