3 Features You Absolutely Need in a SPA
Uh oh, someone broke your HTML app! Those darn users pressed the back button and just lost all the changes they made on the previous View! And you put all that work into building an amazing View and ViewModel pair … sigh. You coded all these great View and ViewModel (aka VVM) pairs but how do you marry them together and display them in your browser in the appropriate area?
What You Need To Know
These are issues that many HTML app developers face. You could code this “plumbing” yourself but it would quickly become something you’d feel should be shared to all of your projects. You need to handle application life-cycle for those common situations. When does your VVM load? When does it go away? What if you want to prevent (or at least interrogate) a user leaving a View/ViewModel? How do compose the View and the ViewModel? App life-cycle and VVM Composition is a critical piece of an app. How do you intercept url navigation and keep the user on the client? These 3 areas are where Durandal can really make a positive difference.
- URL Routing
- VVM Composition
- App Life Cycle
Learn more about Durandal and these topics from my beginner level SPA JumpStart course for Pluralsight, available now.
Durandal
In a SPA it’s pretty darn important to be able to show a View, pair it with a ViewModel, and be able to hook into events in the app’s life-cycle. Durandal makes this super simple. You may not have heard of Durandal before as it is a newer player in this field, but it is built by the makers of Caliburn Micro, a very popular MVVM framework for .NET and XAML. It follows convention over configuration, which simply means if you name things certain ways, they just work. Kind of cool :) Of course you can override those conventions yourself too.
Is it worth learning? Yes! I rewrote my entire demo app in just a few days using Durandal and was able to reduce the code base considerably, and end up with a more fully featured app. The end result was well worth it and you will see Durandal through my course and as a featured player in Hot Towel.
Sure, Durandal has a lot of features, but let’s focus only on these 3 areas any serious SPA has to deal with: routing, app life-cycle, and composition.
URL Routing
Most apps have more than 1 View. So how do you go from View A to View B in a SPA without hitting the server for a page refresh? The answer routing (aka navigation). Let’s say you have a Sessions View and a Speakers View. You want to navigate from one to the other and stay on the client. Durandal can you help you do this.
You simply tell Durandal which routes to listen for. When It sees a route in the address bar it does a pattern match against it and if it is a route you defined, then it will not go to the server and instead it will marry up the V and VM pair.
// Inside a shell ViewModel// Get the router module (Durandal provides this)
var router = require('durandal/plugins/router');// Define the routes and look
// for a V and VM pair both with the
// same name, by convention
router.mapNav('sessions');
router.mapNav('speakers');function activate() {
// Tell the router to start listening for
// routes and where to start
return router.activate('sessions');
}
You can override the default conventions and place your V and VM anywhere you want, but this code shows the easiest path. Make careful note that the activte method has a return statement. Durandal runs on promises, which are the promise that a method will return an answer to the code. The activate method of this code is called (we’ll see more in a bit on this) and waits to hear back for the code to be done. This is where the return router.activate statement kicks in. Without this, the caller would not know when it was done.
VVM Composition
You can put a V and VM together anywhere you like in the HTML. Usually I name my root HTML page shell.html. This is like my master page where I lay out the set of areas I want to compose V and VM pairs. I may have a header, content and footer areas, vertically. Or perhaps a dashboard with 4 content areas, 2 tall by 2 wide. How you lay it out is up to you.
Once a route is invoked you want to pair the V and VM and make the V appear in the right area. We do this through composition. Notice the image below shows the HTML section
tag contains a compose
binding. This is a custom Knockout binding that Durandal uses to help you compose the V and VM.
The section
tag will go get the current item that was navigated to and find its V and VM pair. It will place the View in this HTML tag and when it is done, it will invoke the afterCompose
(this is a handy feature that enables things like turning of a progress bar while composing). You can also use the entrance
transitionwhich comes with Durandal or write your own to animate the arrival of the V.
If you want more areas, just create more HTML tabs and compose bindings. You can also make a V share a VM, as I explain more in my course. This is handy for composing a few Views that all share a VM.
App Life Cycle
The life-cycle of your VVM pair is important. You may need to load data when you crank up a VVM pair. Maybe you want to perform some logic before you leave a VVM pair. You can do this easily with Durandal.
Durandal will look for these 4 methods in your VM. When one of the events occurs, Durandal will look in your VM and if it finds one it will invoke it. They are pretty self explanatory.
- activate
- deactivate
- canActivate
- canDeactivate
If you want to cancel one of the can
events, then return false.
// Inside your ViewModel var canDeactivate = function () { var title = 'Do you want to leave?'; var msg = 'Navigate away and cancel? '; return app.showMessage(title, msg, ['Yes', 'No ']) .then(function (selectedOption) { if (selectedOption === 'Yes ') { // Call some cancel function cancel(); } return selectedOption; }); }; return { activate: activate, canDeactivate: canDeactivate //, //... };
There is so much more you can use Durandal to do, but these 3 concepts are absolutely huge in helping build a SPA. If all you use it for are these 3 tips, then you are getting your value.
Next time I’ll talk a about how to get rich data using BreezeJS.