Single Page Application in MVC 4 Application Using Sammy.js

In this article we are trying to learn how to create single page application with the help of java script library (knockout.js) and Sammy.js (Client Side Navigation Library).

Overview

In this article we are trying to learn how to create a Single Page Application using a JavaScript library (knockout.js) and Sammy.js (Client-side Navigation Library). We will use the MVC 4 Basic template for this demo.

What is Single Page Application?

A Single Page Application or Single Page Interface is a web application or web site that will have only one page. The page does not re-load at any point in the navigation process. For server communication we use Ajax calls and update the sections appropriately. Client-side navigation is done using Hash based techniques.

Knockout.js

JavaScript implementation of a Model-View-ViewModel pattern. It helps in:

  1. Binding ViewModel with View using Declarative Binding.
  2. Automatic UI refresh when changed in the ViewModel properties.

Sammy.js

Sammy.js is a JavaScript library to help us implement client-side navigation.

Getting Started

Let us create the demo application and learn step-by-step. Here we are trying to create a single page where the user can browse the list of products, edit the existing product and delete the product. We will create a single page to perform all these operations.

1. Open Visual Studio 2012 and create a new MVC 4 project and select the Basic template as below.

MVC4 project

MVC4 project Template

2. Now we have the solution ready.

solution-Explorer

3. Now let's create a new controller class by right-clicking the Controller folder. Select "EmptyMVCController" in the Add Controller dialog.

Now we have our controller ready with an Index action.

EmptyMVCController.jpg

Now go to "App_Start" -> "RouteConfig.cs" and update the default route so that when we run the application our product controller's Index action is called.

RouteConfig

4. Now let's create the View ("Index.chtml"). Go to "ProductController", right-click on the Index action and click on "Add View".

Add View

We are ready with our view that has been created under the "Views" -> "Product" folder.

Created View.jpg

Now we are ready to run our application. We should be able to see the Index page.

run our application

5. Now let's start creating the ViewModel. We will name it "ProductViewModel".

Create a new folder "Application" under the "Script" folder. Add a new JavaScript file in the Application folder. We will name the JavaScript file "Product.js".

Now we will create the Product model class in JavaScript. Here we are using the object oriented JavaScript syntax. Also make all the properties observable, this will help us to leverage the declarative binding concept of Knockout.

model class in JavaScript


No we will create our ViewModel and name it "ProductViewModel" in the same "Product.js" file.

To understand the concept of declarative binding and observable properties, we will initially keep only one property in the view model.

We will name it "currentProduct", this property will hold the current product information. For now create a new Product object, initialize it with some dummy values and assign it to the "currentProduct" property.

Now our Product.js will look like as below.

currentProduct property

6. Now the next step is to bind our ViewModel ("ProductViewModel") with the view which is "Index.chtml".

7. Now we need to add reference of Knockout.js. Go to "App_Start" -> "BundleConfig.cs". Add the new script bundle as below.

Add the new script

Go to "_Layout.chtml" and update the code as below.

Layout

Now go to "Index.chtml" and the changes in the following screen shot. Here we are adding the reference of "Product.js" and also binding the "ProductViewModel" to the view using the "applyBindings" function of the Knockout library.

Index

Now we will see how to bind the ViewModel properties to UI controls. Just to explain the concept I will use one TextBox and one label and bind the productName to both controls.

Add the following code in the "Index.chtml" file.

Add the following code in the Index

You can see that we have used the data-bind attribute for binding. First we bound the "<div>" with the "currentProduct" property of ProductViewModel using WITH binding so that we can access the properties of the Product object that has been assigned to currentProduct.

Now run the application and you should see the following output.

run the application

Because of the use of declarative binding we can see the product name shown on the UI. Now since we have bound the same property to both text and label, if we change the text box value then it should automatically be reflected in the label.

Now try to change the text box value and tab off. You should see the following output.

Application output
This proves that we have implemented MVVM correctly.

Now we will return to our actual UI that we had planned to show, the list of products and the user can edit and delete the product.

Remove the following code from "Index.chtml".

Remove the code from Index

Now we will update the ProductViewModel as per the requirements. We need a list of products. So add the products property into ProductViewModel to hold the list of Product objects.

update the ProductViewModel

Here we are taking observableArray to hold the list of products so that it automatically refreshes the UI when we add/remove items to this list.

Now since this a Single Page Application we will create two sections on the same page, one section to show the list of products and another section to display the product information in edit mode.

Let's have two DIV sections as below.

DIV Section

I have made the Product List section visible by default.

Now let's add some UI code to populate the list of products. Please use the following screen shot and update the Index.chtml.

update-the-Index

Here we used the foreach binding on the "<tbody>" tag and it will automatically iterate through the observableArray of products and create "<tr>" tags based on the product count.

Now run the application and you should see the following output.

application-output

Now we will render two action links for each product to edit and delete that product.

Make the highlighted changes in Index.chtml.

changes in Index

Here we are using click binding and calling the "editProduct" and "removeProduct" functions of ProductViewModel. Now let's create the editProduct and removeProduct functions.

When the user clicks on the Edit link, we should present an interface where he/she edits the currently selected product information. The Product Code field should be disabled. Let's create the UI for editing the product.

create the UI for editing

Here we are binding with the currentProduct property of ViewModel. Let's create this property. By default I initialized the currentProduct with blank values.

ViewModel

Now when the user clicks on the Edit link we need to redirect to the Edit Product section. In other words we need to navigate from one section to another in the same page and to do this client-side navigation we will use a small web framework from Sammy that uses the hash based navigation.

You can get the JavaScript library from http://sammyjs.org/ . Save the file in the Script folder and name it "Sammy.js".

Also refer to it in "_Layout.chtml".

Add the new bundle for Sammy.js.

JavaScript library


_Layout.chtml

Layout


First we need to configure all the routes in our application. Add the highlighted code to ProductViewModel.

configure all the routes in application

Here we are calling one function from Sammy.js to configure our route. The route, "#:product/:productCode", is mapped to "/product/[productCode]".

When we change the Location.Hash, Sammy will capture the path assigned to the hash and match with the configured routes, if it matches it will invoke the associated code block.

Now let's add the editProduct and removeProduct functions to ProductViewModel.

adding functions to ProductViewModel

Here you can see that in the editProduct function we are just setting the Hash. Because of the Knockout binding mechanism we get the product object that is bound to that row. In the Sammy function the code block will be executed automatically for a specific route. In our case we are just hiding the product list div and showing the edit product div.

Now when you run the application, you should be able to see the following output.

output

Now when you click on "Edit", you will see the Edit Product section visible, that we are doing in the Sammy function.

Please observe the URL in the address bar in the following screen shot.

  Edit Product

We still don't see product information populated in the fields, because we did not set the currentProduct yet. Let's add one more function "getProduct" that will be called from the anonymous function associated with the route "/product/[ProductCode]" . In the getProduct function we are just traversing the observableArray and matching the selected product based on the product code. Also setting the currentProduct property.

setting the currentProduct property

Update the Sammy function as below.

Update the Sammy function

Now run the application, you should be able to see the output as below.

run the application and Output

Now try to change the product code directly in the address bar and see the behavior.

change the product code in the address bar

When we change the URL in the address bar, Sammy captures the URL and it matches with the route we configured and the code block associated to that route is executed.

Conclusion

So in this article I tried to explain how to leverage the power of Knockout (JavaScript Implementation of the MVVM pattern) and the small web framework to do client-side navigation to create a Single Page Application.