I am learning from John Papa’s "Single Page Apps with HTML5, Web API, Knockout and jQuery" on Pluralsight. The course outlines building an application called "Code Camper". The "Code Camper" sample is very effective at showing an end to end SPA design. It leverages a bunch of open source libraries and can be a lot to take in all at once. One of the libraries used is called Sammy.js. I decided it would be beneficial to focus on just Sammy.js library which is the focus of this blog post.
If you are like me, then you are also new to Single-Page Applications. I find it helpful to start with a simple definition. Wikipedia defines SPA as a "web application… that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application. In an SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load, or partial changes are performed loading new code on demand from the web server, usually driven by user actions."
ASP.NET MVC versus Single Page Application
Suppose you have an HTML, JavaScript and CSS application loaded in a browser. If you look at the home page source, you might notice a series of anchor elements containing hypertext links to other areas within your application such as an "About" page. If you build an SPA version of this application versus a traditional ASP.NET MVC version, it would be difficult to tell them apart by inspecting the HTML only. The anchor tags would look very very similar if not identical.
In a standard MVC application, when the User clicks on the "About" hyperlink, MVC’s routing would find the server-side controller which would create an HTML page on the server and navigate the browser to this new page.
In an SPA, when the User clicks on the "About" hyperlink, the client side HTML is dynamically manipulated all within the client’s browser using standard HTML, JavaScript and CSS. Since a costly server trip is avoided, the result is typically "a more fluid user experience". To pull this off, typically an SPA loads more data in memory upfront to enable the application to stay on the client.
Sammy.js is an open source library that Code Camper leverages to help pull off the SPA behavior but at the same time keep all the good things the browsers do for us such as history management, etc. It's pretty slick.
For me, the following question captures one of the cool features of Sammy.js: "How can I create a standard HTML anchor tag that when the user clicks, instead of requesting a resource on the server, I can intercept the request on the client and call a JavaScript function?" Let me show you an example that answers this question. This example is a modified version of the example provided in the following blog post.
http://mikehadlow.blogspot.com/2010/11/sammyjs.html#/ My version mimics how Code Camper works as well. Thanks Mike Hadlow for this very simple example.
Step by Step
Create a new ASP.NET MVC4 Internet Application Project called "MVC4Sammy or download the finished code here.
Right click on References and click on "Manage NuGet Packages…". Search for Sammy.js and click "Install".
In the root of the project, add an "MVC 4 View Page (Razor) called "Index.cshtml".
1: <!DOCTYPE html>
2: <html>
3: <head>
4: <meta name="viewport" content="width=device-width" />
5: <title>Sammy Test</title>
6: <script src="Scripts/jquery-1.8.2.js"></script>
7: <script src="Scripts/sammy-0.7.2.js"></script>
8: <script src="Scripts/sammy_test.js"></script>
9: </head>
10: <body>
11: <div id="header">
12: <h1>Sammy Test</h1>
13: <a href="#/one">one</a>
14: <a href="#/two">two</a>
15: <a href="/#three">three</a>
16: <a href="HtmlPage1.html">HtmlPage1</a>
17: <a href="http://www.promodel.com">ProModel</a>
18: </div>
19: <div id="main">
20: <section class="main">
21: @RenderPage("Views/Partial1.cshtml")
22: @RenderPage("Views/Partial2.cshtml")
23: @RenderPage("Views/Partial3.cshtml")
24: </section>
25: </div>
26: </body>
27: </html>
28:
Delete all the files from "Views" folder. Right click on the empty "Views" folder and Add a partial "View
" called Partial1
.
Put the following code in Partial1.cshtml.
<section id="partial1-view" class="view">
<div>Hello from Partial 1</div>
</section>
Repeat for Partial2
and Partial3
but change the section ids.
Add a new "JavaScript file" in the "Scripts" folder called "sammy_test.js". Put the following code:
1: (function ($) {
2:
3: var app = $.sammy('#main', function () {
4:
5: this.get("#/one", function (context) {
6: $(".view").hide();
7: $("#partial1-view").show();
8: });
9:
10: this.get("#/two", function (context) {
11: $(".view").hide();
12: $("#partial2-view").show();
13: });
14:
15: this.get("/#three", function (context) {
16: $(".view").hide();
17: $("#partial3-view").show();
18: });
19: });
20:
21: $(function () {
22: app.run('#/');
23: });
24:
25: })(jQuery);
Modified root Web.Config webpages:Enabled
to true
.
Add a new "Html Page" to the root called "HtmlPage1
". Put any text in the body.
Set Index.cshtml as Start Page and Run.
Highlights
Similar to Code Camper, this example MVC4 SPA creates a root view called "index.cshtml" containing a series of @RenderPage
calls against some partial views. The partial views represent the various modules within an application. Each partial view is declared within a "Section
" element with a unique id and a shared class called "view
".
In the "sammy_test.js" file, you will see code registering "get
" routes with JavaScript functions such as:
When the user clicks on a link that goes to "#/one
", that function will be called instead of requesting a resource from the server. The JavaScript code hides any element with a class called "view
", then immediately shows any element with an id value of "partial1-view
".
There are probably a million ways to do this, but this example shows how the client is dynamically manipulated without going to the server.