Welcome back! This post is the last part of our ground-up tutorial. Our aim is to show the feasibility of interfacing the famed Backbone Todo demo with a REST ASP.NET backend.
You can find previous parts at:
- ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part I
- ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part II
- ASP.NET MVC3 RESTful application tutorial with Backbone.js – Part III
Let’s have a brief recap: in the first part we only set up our dev environment with a database and a Visual Studio solution, in the second we created the Model on top of Entity Framework 4 and in the last we dealt with the Controller outlining all the REST actions. You can find up-to-date code for this tutorial at this link.
Today we will complete our recipe about our well-known ASP.NET MVC3 application, working with the View, garnishing it with Backbone.js. We will have an overview about Backbone, then analyze a bit the structure of the Todo demo and in the end we will easily brush our application with Backbone’s Todo files.
Backbone.js
Backbone.js is a Javascript framework based on the handy MVC architecture. The main point of choosing Backbone for your dynamic applications is the structuring you gain in the process. It gives you a score of best practises to logically divide your everyday’s work as opposed to simply write messy javascript code tied up with DOM elements. We call it an MVC framework for the View.
In Backbone a Model can be pretty much everything, but at its core it is the interactive data of your application, together with the methods to modify it. Collections are an handy addictions: they handle model additions, changes and deletion. If we look at the Todo demo js file we can spot a Todo model
window.Todo = Backbone.Model.extend({
// ... a couple of functions ...
});
and a Todo Collection. Pay attention to the localStorage line, we will change it later.
window.TodoList = Backbone.Collection.extend({
model: Todo,
localStorage: new Store("todos"),
// ... some other functions ...
});
The object named View in Backbone can be a bit confusing, as it can be considered the real Controller of the application: it reacts to user interactions and dispatches events. It is bound to a DOM element and in charge of a part of the UI, but does not deal directly with HTML elements.
window.TodoView = Backbone.View.extend({
tagName: "li",
template: _.template($('#item-template').html()),
events: {
"click .check" : "toggleDone",
"dblclick div.todo-text" : "edit",
"click span.todo-destroy" : "clear",
"keypress .todo-input" : "updateOnEnter"
},
initialize: function() {
this.model.bind('change', this.render, this);
this.model.bind('destroy', this.remove, this);
},
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
...
return this;
},
// ... more functions ...
});
To draw the page Backbone relies on a templating engine, which is the real View in a traditional MVC sense. Backbone is agnostic with respect to the HTML template: you are in charge of the choice: we usually like Mustache.js.
Underscore.js is the only dependency for Backbone and in fact this demo dodges the use of other template engines and instead relies on it, as you may notice looking at the the _.template function attached to the template property in the previuos View of the Todo model
Here, instead, you find the template for that view with id item-template
[...]
<script type="text/template" id="item-template">
<div class="todo <%= done ? 'done' : '' %>">
<div class="display">
<input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
<div class="todo-text"></div>
<span class="todo-destroy"></span>
</div>
<div class="edit">
<input class="todo-input" type="text" value="" />
</div>
</div>
</script>
[...]
As a convention, AppView is a special View that is the entry point of a Backbone application and it’s triggered by a “jQuery.ready” function. In this demo it initializes the Todo collection fetching the models, sets the list up and binds the proper events to their delegates.
$(function(){
[...]
// Our overall **AppView** is the top-level piece of UI.
window.AppView = Backbone.View.extend({
[...]
});
// Finally, we kick things off by creating the **App**.
window.App = new AppView;
})();
Good! Now you have at least the grip of the structure of a very simple Backbone app. Let’s get our hands dirty!
Cleaning up your project
Before dealing with the Todo demo files we will clean our VS solution to remove any trace of the standard bluish template. Delete every file into the “Content” directory (both the theme folder and the css file). Then delete the “AccountController” in the “Controllers” folder, then the “Views/Account” folder together with “Views/Shared/_Layout.cshtml”, “Views/Shared/_LogOnPartial.cshtml” and “Views/_ViewStart.cshtml”. Finally delete every js file in the “Scripts” folder except jquery-1.4.4*. You can find in this archive every file you need (png, css, html, js), directly from the Todo demo (thanks to Jérôme for the permission to redistribute them!). You could just unpack the archive in the main solution folder and then we will work on these files; replace if needed.
Now a bit of (tedious but necessary) housekeeping… In the solution explorer in VS (Right click on the “Scripts” folder) Add –> Existing Item and add “Scripts/underscore-1.1.6.js”, “Scripts/backbone.js” and “Scripts/todos.js”. (Right click on the “Content” folder) Add -> Existing Item and add “Content/destroy.png” and “Content/todo.css”.
Let’s now fix the paths. Open “Content/Home/Index.cshtml” and replace the existing head section with this Razor empowered snippet of code
<head>
<title>Backbone Demo: Todos</title>
<link href="@Url.Content("~/Content/todos.css")" media="all" rel="stylesheet" type="text/css"/>
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")"></script>
<script src="@Url.Content("~/Scripts/underscore-1.1.6.js")"></script>
<script src="@Url.Content("~/Scripts/backbone.js")"></script>
<script src="@Url.Content("~/Scripts/todos.js")"></script>
</head>
Changing Persistence
As we have noted before, the demo overrides “Backbone.sync” (the facility to load/save models to the server), relying on localStorage for persistence. Of course, this is quite useful for fast prototyping the application, but it is in contrast with our requirements. We need in fact to store our data using the ASP.NET/SQL backend. We have already deleted the reference to the Backbone-localstorage library, but the application still tries to use this persistence module. Adding support for REST-based persistence is as easy as changing the localStorage line we marked before, with the url to the REST APIs. Open “Scripts/todos.js” and change
localStorage: new Store("todos"),
with
// Use REST url instead of localStorage facility
url: function () {
return "api/Todos" + (this.get('id') ? '?todoId=' + this.get('id') : '')
},
And voilà! Our dish is ready at last! You can now run the project and try the working demo. If you like these tutorials show some support in the comments ;)
Final version of the application: Download
Extension
Backbone’s documentation suggests that
when your app first loads, it’s common to have a set of initial models that you know you’re going to need, in order to render the page. Instead of firing an extra AJAX request to fetch them, a nicer pattern is to have their data already bootstrapped into the page. You can then use reset to populate your collections with the initial data.
We will change our example to add model prefetching capability.
Let’s write a simple extension method as helper to deal with JSON serialization.
(Right click on “Todo” Project in the Solution Explorer) Add –> New Folder. Name it “Helpers”. Then (Right click on “Helpers” folder) Add –> New Item –> Visual C# –> Web –> Class. Name it “JsonHelper.cs” and click Add. The code for the helper is here
using System.Web.Script.Serialization;
namespace Todo.Helpers
{
public static class JsonHelper
{
/// <summary>
/// Converts an object to a JSON string.
/// </summary>
/// <param name="obj">The object to serialize.</param>
/// <returns>The serialized JSON string.</returns>
public static string ToJson(this object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
}
}
Then comment the
Todos.fetch();
line, way down in “todos.js”. In the end, the “Index.cshtml” needs a couple of edits. At the top of the file add
@model IEnumerable<Todo.ViewModels.TodoViewModel> @using Todo.Helpers
and before the “templates” section add
<!-- Prefetch -->
<script type="text/javascript">
$(function () {
Todos.reset(Todos.parse(@Html.Raw(Model.ToJson())));
});
</script>
Prefetching enabled! Hope you enjoyed the effort ;)









