A very trendy topic recently has been Single Page Applications. In this article I’m going to show you how to build a SPA with the new HotTowel Visual Studio template. The HotTowel project template includes technologies such as WebAPI, Breeze, Knockout and Durandal among others. It is a very good starting point for building data driven Single Page Applications. Thanks to John Papa for creating this VS template and for all the resources he provides on his personal website and the courses @Pluralsight.
You should know that there are many other SPA project templates coming with the recent ASP .NET and Web Tools 2012.2 Update. I chose this one because it provides a lot of functionality and out of the box it’s a functioning website. I personally am more of a backend developer and Javascript is not my strength. That said, I think this and the following blog posts in the series will be a good example for beginners on how to build a SPA.
The article will show you how to do the following:
- Build a model.
- Expose the model with the Breeze WebAPI.
- Consume the model on the client side with BreezeJS.
- Build a viewmodel and make queries to the data with Breeze.
- Build a view and bind the data with KnockoutJS.
- Add routing on the client side.
- Use DurandalJS to make it all work together.
Building the model
We’ll create a simple model with Entity Framework Code First. The model three classes – RestaurantBrief, Restaurant and Location. Note that RestaurantBrief is not a real model, its purpose is to store partial restaurant data to reduce the payload going to the client when querying a large number of restaurants.
public class Location { public int LocationId { get; set; } public double Latitude { get; set; } public double Longitude { get; set; } } public class RestaurantBrief { [Key] public string Id { get; set; } public string Name { get; set; } public string Address { get; set; } public string Description { get; set; } } public class Restaurant : RestaurantBrief { //[Key] //public string Id { get; set; } //public string Name { get; set; } //public string Address { get; set; } //public string Description { get; set; } public string CoverPhoto { get; set; } public double Rating { get; set; } public Location Location { get; set; } }
Expose the model to the client side with Breeze
To expose the model to Breeze on the client side we simply implement a Breeze Web Api controller as shown below. This is an ApiController with a special attribute [BreezeController]. The Metadata method describes the entities to the client; the SaveChanges method saves a set of entity changes sent by the client in JSON format. I’m also using the provided by Breeze EFContextProvider, it’s basically a wrapper around the Entity Framework DbContext. You can find more about the features used here in the documentation of Breeze @http://www.breezejs.com/documentation/introduction
[BreezeController] public class RestaurantController : ApiController { readonly EFContextProvider _contextProvider = new EFContextProvider(); [System.Web.Http.HttpGet] public string Metadata() { return _contextProvider.Metadata(); } [System.Web.Http.HttpPost] public SaveResult SaveChanges(JObject saveBundle) { return _contextProvider.SaveChanges(saveBundle); } [System.Web.Http.HttpGet] public IQueryable Restaurants() { return _contextProvider.Context.Restaurants; } [System.Web.Http.HttpGet] public IQueryable RestaurantBriefs() { return _contextProvider.Context.Restaurants.Select( restaurant => new RestaurantBrief { Id = restaurant.Id, Name = restaurant.Name, Description = restaurant.Description, Address = restaurant.Address } ); } }
Consuming the model on the client side with Breeze JS
You can query data from the WebAPI controller on the client side very easy using the Breeze Entity Manager. Note that the syntax is very similar to the one used frequently on the server side. This is quite useful for someone like me for example. The query is asynchronous and returns promises such as then and fails. Promises return the result of a task and we can chain them easy. They are a rather new and more complex topic in javascript and you can find more about them online. Promises are not covered in this article.
To get all the restaurants we use the following code:
var serviceName = 'api/Restaurant'; var query = breeze.EntityQuery. from("Restaurants"); var restaurants = manager .executeQuery(query) .then(querySucceeded) .fail(queryFailed); function querySucceeded(data) { alert("Success!"); } function queryFailed(error) { alert("Query failed: " + error.message); }
Building the viewmodel and querying data from the server with Breeze JS
Defining the viewmodel is as basically querying the web api and returning a knockout observable object. We must implement an activate function which should get the data and bootstrap the viewmodel. It is implemented using the module pattern using Require.js. On the client side we will later bind the title of the view and loop through the restaurantBriefs observable collection to display each of the results. We’re using toastr (a javacript library by John Papa) to show notifications on the client side.
define(['services/logger'], function (logger) { var vm = { restaurantBriefs: ko.observableArray(), activate: activate, title: "Restaurants View" }; var serviceName = 'api/restaurant'; var manager = new breeze.EntityManager(serviceName); function activate(context) { return getRestaurants(); } function getRestaurants() { var query = breeze.EntityQuery. from("RestaurantBriefs"); return manager .executeQuery(query) .then(querySucceeded) .fail(queryFailed); function querySucceeded(data) { vm.restaurantBriefs(data.results); toastr.success("Restaurants loaded!"); } function queryFailed(error) { toastr.error("Query failed: " + error.message); } }; return vm; });
Building a view and binding the data to the view with Knockout JS
The view below will simply write 3 rows for each RestaurantBrief returned from the WebApi controller. We’re using Knockout to loop through the collection and do the binding. Note that we’re binding the href attribute of the anchor node to ‘#/restaurant/’ + Id. This is a route we’re defining in the next section. Routes on the client side are very similar to routes in Asp .Net.
</pre> <section> <h2 class="page-title">Resturants View</h2> <div class="grid" data-bind="foreach: restaurantBriefs"> <div class="column"><a data-bind="attr: { href: '#/restaurant/' + Id }"> <span id="name" data-bind="text: Name"></span> </a> <span id="address" data-bind="text: Address"></span> <span id="description" data-bind="text: Description"></span></div> </div> </section>
Adding routes on the client side
To add a route simply call the mapNav function of the router module – as shown below. We’re doing that in the boot function of the shell.js viewmodel. Shell.js is a special viewmodel that bootstraps the application.
You can find here the routes used for the viewmodel we’ve created (restaurantBriefs) and another route we haven’t yet created a viewmodel and a view for but we already have hyperlinks using it. This route will be used in the next article.
function boot() { router.mapNav('home'); router.mapNav('details'); router.mapNav('restaurantBriefs'); router.mapRoute('restaurant/:id'); return router.activate('restaurantBriefs'); }
Adding routes with parameters.
Making it all work together with Durandal JS
Durandal JS is a Single Page Application framework which provides modularity, event handling and application lifecycle services. It provides us with the necessary tools to avoid a lot of the painful plumbing and have a good code structure.
What’s next?
In the next article I’m going to show you how to create parameterized routes and we’re going to create a restaurant view and viewmodel. We’re also going to add filtering and caching of the data on the client side to optimize the performance. We’re going to discuss more complex Breeze queries and we’re going to find more about Durandal JS.
Other articles in this series
- Building a SPA with the HotTowel Template – Part One
- Building a SPA with the HotTowel Template – Part Two
- Building a SPA with the HotTowel Template – Part Three – Validation
- Building a SPA with the HotTowel Template – Part Four – Real-Time Communication
- Building a SPA with the HotTowel Template – Part Five – GRID
The post Build a Single Page Application with the HotTowel SPA Template – Part One appeared first on Georgi Stavrev.