Build Single Page Apps – Part 9 – Navigation, Transitions, Storage, and Messaging | John Papa

John Papa

Evangelist on the loose

Build Single Page Apps – Part 9 – Navigation, Transitions, Storage, and Messaging


I like demo apps that show how to deal with real scenarios like navigation, animation, client storage, and event messaging. A SPA generally has multiple views of related data and uses navigation so it only makes sense that my new Pluralsight course “Single Page Apps with HTML5, ASP.NET Web API, Knockout, and jQuery” demonstrates navigation. And frankly, the rest of the topics like animations and storage were just too cool to leave out.


You can catch up on the previous posts in this series here:

More on the Code Camper SPA

Part 1 – The Story Begins (What is the Code Camper SPA?)

Part 2 – Client Technologies

Part 3 – Server Technologies (the Data Layer)

Part 4 – Serving JSON with ASP.NET Web API

Part 5 – HTML 5 and ASP.NET Web Optimization

Part 6 – JavaScript Modules

Part 7 – MVVM and KnockoutJS

Part 8 – Data Services on the Client

Part 9 – Navigation, Transitions, Storage and Messaging

Part 10 – Saving, Change Tracking, and Commanding

Part 11 – Responsive Design and Mobility


I had a few goals for navigation and I covered them all using Sammy.js and its hash based navigation/routing. See the image below for some of the features I implemented.


If I had wanted to use HTML5 pushState (not yet supported consistently in all modern browsers) I likely would have chosen differently. But I wanted the demo to work in a very broad set of browsers, so I decided to stick with Sammy’s hash based navigation. I am a fan of modularity so I wrapped up Sammy in a module I named my router. So if I wanted to swap it out later, it’s trivial.


When flipping between different views, I wanted animations. I didn’t need them of course, but I wanted them to provide a subtle UX. So I chose to create a fade in and translation for my views. I wrapped this functionality into, you guessed it, a module (named “presenter”).

Sammy catches the route, it tells the viewmodel to activate itself, then it uses my presenter module to transition the View into place.


Storage and Messaging

I wanted my users to be able to shut down the SPA and when they come back in, the app brings them right back to where they left off. For this, I used the browser’s storage. AmplifyJS made this dead simple and it hooks right into my router. The cool thing about this library is that it works all the way back to IE 5 according to their docs. It figures out what the browser supports, chooses the most modern storage type, and uses it.

I also had a need for a pub/sub message in the demo. For you XAML folks think EventAggregator in Prism or Messenger in MVVM Light. AmplifyJS helped out with that too.


I could have used the click event for all of my buttons. But I wanted to build functionality in for handling:

  1. disabling the button while it is executing
  2. handling async commands
  3. disabling the button when it is inappropriate to use


Leaning on my XAML experiences I worked with my friend Hans to build a asyncCommand object and we packaged it up, made it part of a library called KoLite, and posted it to GitHub and NuGet. You can learn more about KoLite and its commanding features on GitHub. I’ll be blogging more about this library in the coming weeks too.

What Else

What else is in the course? Actually there is quite a bit more. Next up I’ll talk about saving data, change tracking, and more!

tags: amplify html5 javascript jquery pluralsight sammy SPA
  • Ryan Keeter

    Great series, and I am enjoying it immensely. I find it very hard however to follow the series without the source code (though I wouldn’t gain even a quarter of the insight with the source code and no videos), and wanted to know if you will make the source code available.
    I may be wrong, but as the format of this course is similar to the format of Mr. Wahlin’s Account At A Glance application (for which you helped on), I thought you would release the source in the same say that Mr. Wahlin released the source (to aid followers of the video series).
    Thank you, and great series!

  • Fritz Onion

    Hi Ryan,
    We’re really glad you’re enjoying the course (and couldn’t be happier ourselves with the work John put into it). Part of our business model is to provide incentive for subscribers to upgrade to ‘plus’ accounts, and downloading the code for courses is part of that upgrade. Dan Wahlin’s course was a bit of a special case because the code was already released through Microsoft and he gained permission to reuse it in his course.
    Thanks for understanding.
    -Fritz Onion

  • Brooks

    Hello John. Thank you for the course. I’m going through it now and it’s very informative.
    I did have a question (or two). I’m in the process of developing my own SPA, so I figured I’d follow the recommendations of the course (makes sense). However, I used Nuget to get the various JavaScript 3rd party libraries and was overwhelmed by the number of files download and put in my project.
    For example, installing requirejs, also installed things like cs.js, domReady.js, i18n.js, r.js, etc. Also, for libraries like infuser, koExternalTemplateEngine, and TrafficCop, Nuget gave me a lot of files such as:
    And, then there’s sammy. It created it’s own subfolder under the normal Scripts folders and added 43 different files!
    Anyway, my main question is what are all these extra files and do I need them?
    What are the *-amd* files? What are the *gz* files? What do I do with all the sammy files?
    I guess it comes down to: what is the minimum set of files do I need or should I just bundle up everything that Nuget gave me?

  • john

    That’s a great question. I have found that many of the NuGet packages give you much more than you need. I often use it, then delete what I dont want because it can get to be messy (like you said). The gz files are gzipped versions, which are smaller. -amd files are versions of the library that are “AMD ready” for requirejs. In general you just need to pick one flavor of all of those files and use it, then remove the rest.
    In one of my upcomng posts on SPA’s I’ll post more info on how I choose. But for now if you have more questions, feel free to put them here or on twitter at @john_papa

  • Egzon

    Hi John … i saw some of modules of SPA screencast and they are wonderful.
    It`ll be great if you can add a post on this series writing about authentication and roles in SPA. Its a little challenge, especially when the developers are used to let web framework to care about that. Which are the best practice? To store some kind of sessionId on cookie and on each request to send like a parameter that id. Or are another options about that?

  • Andrew

    Hi John, I saw this course at Pluralsight. Thank you.
    But Ergon right. It woud be nice to see how and what the best practices to authenticate users in the SPA.
    Thank you in advance.

  • john

    Thanks for the feedback. Authentication could be done using ASP.NET or some other form of auth from the web server. Nothing has changed here from common practices. I wouldn’t store and user sensitive data on the client.

  • Andrew

    Thanks John, but what do you think about splitting a SPA application into two part – one for login/registration, another for SPA application itself. By the splitting i mean creating two controllers, and two views. Or is it better to put all functionality into one SPA (so, only one view in terms of MVC)?

  • john

    I try to think of ways to split my app into mini apps. Where are my related sets of features? If I have those, then I can make a few related SPAs instead of one larger one.
    You can use one view or two views for this. I look at SPA’s as a way to handle a set of functionality. Perhaps you have a new view (and page) just for logging in, and another page for admin screens. Once the data gets becomes less related to the current set of Views’ features, then I start thinking about hitting the server … and a new View … and possibly a new set of features for it.

  • Andrew

    John, thanks for your reply.
    Last question: if you need to apply authentication in your SPA application would you split it or do it in one SPA?
    Thank you in advance,
    and sorry for a big amount of questions from my side.

  • john

    Andrew – No problem. I’m not 100% sure without giving it more thought … but I’d lean towards making a new view for the login. I’d also have authentication throughout the app so it kicks them back out to the login view when not authenticated. ASP.NET auth works great for this. Or possibly the new OAuth

  • Andrew

    John, thank you very much!
    I know, it is stupid question, but is it possible to get .js sources anywhere but not at Pluralsight?
    Thanks again.

  • john

    Sorry, currently just with Pluralsight’s Plus subscription.

  • Sascha

    thank you very much for this presentation, I learned a lot from it!
    In the PSA you use Sammy for routing. Could this be exchanged for the Ember-Routing (with Ember.Layout) to support sub-views like sub navigation bars? Is this even possible with sammy.js because i am struggling with the routing for days and just cant get it figured out how to so this. Any hint would be much appreciated.

  • Chad

    Awesome series, going through it right now on PluralSight. Had one question:
    Does the course speak to SEO techniques for SPA’s? Really concerned about that for some of my apps.

  • Dor Raba

    First of all, I must say, I seen the entire course of SPA on pluralsight, and for sure this is the best course I have ever watched there. Thank you very much. You are the first one who actually let me understand how a good JS code should be built. Just one question about Navigation. If I build a SPA as the CodeCamper project, How can I send my friend a link of the current page I’m watching, lets say of a session page? Is it possible? because as I see it, no matter what Link I’ll send in the email, it will always land on the homepage.

  • john

    Thanks for the feedback, I am glad you are enjoying the course.
    If you send a deep link such as http://yoursite/sessions/14 it will go right to that link. That’s part of what Sammy and the router do for you. For example, try this for the live demo:

    • Dor Raba

      Hi John,

      Thanks, I didn’t realize it, that looks great, Waiting for your next courses :-)

  • Jeff M

    Hey John. Downloaded Breeze beta last week and I’ve been trying to integrate it into your SPA application. I have a feeling that this is an incredible match. Please John… extend your (exceptional) Pluralsight SPA series to include this great product from IdeaBlade!

  • Luc Morin


    I’ve been going over the code from the Pluralsight series, and I can’t quite figure the design decisions behind the way you register routes in CodeCamper.

    In some cases you define the routes as an array of routes, but in others you define the as single routes. And in the case of “Sessions”, you even define an array of routes with a single route in it.

    I’d like to understand why you decided to go that way.

    Thanks, and keep up the good work.


    • John

      Hi Luc,

      I set up various ways to pass in the routes. The arguments can accept different overloads, if you will. Sometimes multiple routes will all point to the save physical View, but with different parameters. That’s where you see the array with the 1 view. Other times I have a route that points to a specific View. I could have used an array, 1 for each route to View (which is where I started). But its repeating the code quite a bit, so I decided to make it accept a few options. Of course, feel free to choose your own path.

      Thanks for the feedback and for watching!

  • Jack


    Thanks for the Pluralsight course. It’s been very helpful for me in learning SPAs, JavaScript, etc. Good stuff!

    Anyway, I’m writing today because I’m having tons of trouble with the routing (and sammy.js). I’ve gone through all the course videos, downloaded and studied Code Camper, and created my own project (in which I copied your code almost exactly, then changed it slightly to fit my project – i.e., sessions -> alarms, session -> alarm, I only have the two views, one hash route #/alarms, etc., etc.).

    First off, I upgraded sammy.js to the latest (v0.7.1, you have v0.6.3 in Code Camper), and that completely didn’t work. The newing of sammy (sammy = new Sammy.Application(function () { …) in router.js would buffer overflow something in whatever that code is trying to do. I even put sammy.js 0.7.1 in Code Camper, with the same results.

    Do you know of any issues with the latest sammy.js?

    After replacing the latest sammy.js in my project with the version in Code Camper, my app would at least work and load the correct start page, but I still have an error. Then when I try to transition from alarms to alarm (like your sessions to session), it doesn’t work and gives an error. The error(s) are coming from sammy.js and are pretty generic – “500 Error get #/alarms response is not defined” and “500 Error get #/alarms/2742 response is not defined”, even though I have my hashes, view IDs, router, router config, etc. all set up almost identically to Code Camper’s sessions and session views.

    Is there some “trick” to making routing work (I mean, beyond the videos)? Maybe I’m missing some minor detail.

    Also, you mentioned in this post “If I had wanted to use HTML5 pushState (not yet supported consistently in all modern browsers) I likely would have chosen differently.”, what would your other choices for routing have been? Is there some other library that will work better/easier than sammy.js?

    Sorry for the long post, but this routing thing is making me crazy.


    • John


      The new version of Sammy appears to have some breaking changes, as you pointed out. I’ll take a look at it when I get some time, but for now I would not upgrade of 0.6.3.

      You could use HTML5 pushstate directly or you use Simple History, which is a small library that wraps it.

      The key with routing and any JavaScript is to use the browser’s debugging tools and walk through it. Examine the Sammy object when it executes and see what routes are being trapped.

  • Jack

    Hi again John. One thing I forgot to mention, I don’t have an .htaccess file in the root of my project as you do in Code Camper. I really don’t know what this file is for, but I thought .htaccess was used for Apache web servers (and, of course, I’m using IIS/IIS Express). What is this file used for? And, could this be causing my routing issues?

    • John

      The .htaaccess file comes with HTML5 boilerplate. You can find out more about it on their site. One thing it includes is caching of images. You could remove this if you like, it won;t affect your routing though.

  • Jeff M

    Your SPA framework loads all the js codebase at once. Would you be hesitant to do this for a larger application? I’ve read about some apps with a pretty huge js codebase (3 to 4 mb) that employed some from of lazy loading – – although I’m somewhat in the dark as to how this would work with your framework. What do you think?

  • Guillermo

    Hi John, great video series, helps a lot to many people. I’m just wondering…What if I want to use backbone.js which seems to have a great momentum in San Francisco? Were will it fit here and what will it be replacing? just knockout?

    • John

      Hi Guillermo,

      Thanks for the feedback.

      You could use backbone, but it covers a different set of features than Knockout. KO handles bindings while backbone does more plumbing for you (and requires a backbone plugin for bindings). Its not a simple swap out.

  • Thad

    Hi, John. Thanks so much for posting Code Camper, it has been invaluable in helping me understand how everything fits together in a SPA. I really like how you wrapped Sammy with router.js and set the config – nice and clean and easy to replace Sammy with whatever.

    I, too, had some issues upgrading Sammy.js to the latest version and I came across this post. I was later able to figure out what’s going on, especially once it dawned on me that we are just giving Sammy a route and a method to call when he encounters that route.

    So here’s what’s going on. Since version 0.7.0, Sammy uses the full path so where we defined the default route as ” before, we now must define it as ‘/’. Also, where sammy.getLocation() would return ” it now would return ‘/’.

    Changing 4 lines of code fixes this is the Code Camper application I downloaded from

    router.js – line 12:
    this.get(‘/’, function () {

    router.js – line 108:
    startupUrl = sammy.getLocation() == ‘/’ ? defaultRoute : sammy.getLocation();

    index.cshtml – lines 18 and 19:

  • Dan Hickman

    Thanks for the series. I have been studying Code Camper and applying to my project. I have having issues getting a new MVC4 application to load a cshtml from the root directory. How did you pull this off? I have researched this and followed the advice online but still get a “does not inherit from ‘System.Web.WebPages.WebPage'”

    I posted a more detailed summary on StackOverflow. What is the secret sauce i am missing?

    • John

      Dan – in web.config, set the enable web pages to true.

  • Dan Hickman

    I recently blogged a very simple tutorial on ASP.Net MVC 4 SPA navigation with Sammy.js that mimics how Code Camper is laid out. My colleagues found it valuable so maybe you will too.

%d bloggers like this: