Thanks to Susan Potter‘s suggestion of tagging the source code on Github, you can download the source corresponding to the application as of the end of each “todo” step! You can find the list of tags here.

1. Create a Shell Application

Note: In this tutorial we will de-emphasize the server framework side and focus on browser considerations.

So let’s start:

Create a root folder for our application named savings-goal-simulator

Create a file named index.html for our main page

Create a folder for our Javascript files named scripts

Create a sub-folder under scripts for our vendor Javascript libraries named vendor

Add the basic markup for a page in index.html

Ok, now we’re ready to add our key external Javascript libraries.
Here is the basic minimum we’ll need with a quick rationale as of why they will help us:

If we want to start authoring HTML 5 semantic pages, Modernizr is a library which can facilitate detection of specific HTML5 and CSS3 features. But it also shines for Internet Explorer versions earlier than 9 by plugging in “shims“, i.e. fake HTML elements in the DOM, named after the new HTML5 missing elements, making it possible to use tags likeheader, footer, section, etc. and styling them too.

You will need to create your own custom version of Modernizr based on the features you need. This will ensure the smallest most effective script for your situation.

For our app, I chose to only include the “HTML5 Shim/IEPP” and the “CSS classes” – see this download configuration. I renamed the resulted file as modernizr.custom.min.js and placed it in the scripts/vendor folder.
So we’ll need to include the script for Modernizr right at the beginning our our HEAD section.

<head>
<!-- Important: Modernizr must be the very first script in HEAD -->
<script src="scripts/vendor/modernizr.custom.min.js"></script>
<!-- ... -->
</head>

For performance reasons, we’ll use a Javascript loader (see available options further on) to ensure the Javascript libraries we’ll need can be loaded asynchronously, in parallel, and not block the execution of our page load.
For this app, I chose LABjs as it is specializes only on loading and is commonly used.
But note that you could use some of the conditional loading features of Modernizr, called yepnope.
I chose to keep things minimal for our app. ;-)

Starting from a basic HTML page, let’s add a script reference to lab.js below our modernizr script, and then let’s define the order in which we want to load our libraries.
We’ll add a call to wait() if we want the execution of the actual code to be order-dependent:

<head>
<!-- Important: Modernizr must be the very first script in HEAD -->
<script src="scripts/vendor/modernizr.custom.min.js"></script>
<script src="LAB.js"></script> <!-- Important: must be the very first script in HEAD -->
<script>
$LAB
.script("http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js").wait()
.script("http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js")
.script("http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js")
.script("scripts/vendor/knockout-1.2.1.debug.js").wait()
.script("scripts/vendor/jquery.cookie.js")
.script("scripts/vendor/jquery.blockUI.js")
.script("scripts/vendor/jquery.hotkeys.js")
.script("scripts/vendor/jquery.maskedinput-1.3.min.js")
.script("scripts/vendor/jquery.validate.min.js")
.script("scripts/vendor/accounting.min.js")
.script("scripts/vendor/jstorage.min.js")
.script("scripts/vendor/raphael-min.js").wait()
.script("scripts/vendor/g.raphael-min.js").wait()
.script("scripts/vendor/g.line-min.js").wait()
.script("scripts/application.js").wait(function(){
// When ALL scripts have been loaded AND executed:
InitializeApplication();
});
</script>
<!-- CSS and other HEAD-specific tags -->
</head>

You will notice that I am assuming a specific directory structure for our locally hosted Javascript code

scripts is the root of all .js files

Vendor will host external vendor libraries not available on a CDN.

Having all external JS libraries in a dedicated folder will keep our directory structure clean.

ViewMediator will include Javascript code mediating interactions between Views and ViewModels

ViewModel will include our ViewModel-specific Javascript code

application.js will be the main application .js file with an InitializeApplication function (called from our $LAB configuration)

At this point go ahead and create the same folder structure and download the needed Javascript libraries for the Vendor folder.
You can use the links in the External Javascript Libraries table above.

And create the application.js file under the root of the scripts folder, and let’s provide a minimal implementation for now:

2. Organize our Application Code

Since our application will very modular and encompass many functions or classes,
we’ll establish a namespace to provide some structure and avoid function name clashes.
You can read more about how to implement namespaces in Javascript in the following two articles:

For this app, we’ll use sgs (for savings goal simulator) as a prefix,
followed by either model or mediator for ViewModel and ViewMediator respectively.
To keep our markup free of Javascript logic, we’ll organize the application code in the following folders:

application.js will contain only logic to initialize / setup the views and viewmodels

So at this point, create the folder structure described above as well as stub content for sgs.model.common.js and sgs.model.common.js (they can remain empty for now). And let’s update the LAB.js section to load these 2 files (before application.js):

Here is a quick synopsis of the architecture for the first increment of our app:

3. Create the Savings Goal View

Now that we have a minimal shell in index.html,
let’s add a section tag to represent our first panel / view: the savings-goal-view.
The view will let us enter a savings goal amout and a maximum number of months.

<body>
<section id='savings-goal-view'>
</section>
</body>

Now we can add the two input elements (savings-goal-amount and savings-max-duration).
And we’ll have a span to display the calculated (derived) savings-target-per-month. This is what the view will look like:

Important Note: In this tutorial, instead of “inlining” the data-binding declaration with the view model inside the markup (like you will see in the KnockoutJS site or on any other simple tutorials), I am proposing a more “unobtrusive” approach consisting of keeping the markup pure and explicitly defining data-bindings separately later (in the view mediator which we’ll see soon in the next section).

At some point in the future, once the number of views increases beyond a couple, we’ll externalize our views as individual [jQuery] template files – but we’ll see the approach in detail later.

Note: as we go along in the tutorial, I will not cover the CSS styling explicitly but you can always get the CSS when downloading the source based on the tag for a given step. Example: tag: part2-todo-2.zip (also available in tar.gz form). Look under for css/application.css

4. Create the Savings Goal ViewModel

If you have not yet created the ViewModels folder under the scripts folder, do that now. And then create a file named: sgs.model.savings-goal.js.

Here is a diagram summarizing what we’re about to implement:

As we indicated earlier, we’ll use namespaces to structure our code and avoid name collisions with other libraries.
There are various approaches for namespacing code in Javascript, some uses object literals, and some use functions as containers for our functions. Elijah Manor has a great summary highlighting the pros and cons of the various approaches.

For our needs and to make it easy to extend and edit our namespace we’ll use the object literals.
To lazy initialize our namespace hierarchy let’s add the following snippet, which checks if each node in our namespace exists and creates it if it is not yet defined.

So our viewModel is basically an object literal (hash) where each property value is a value model,
implemented as KnockoutJS observable, essentially a function acting as an interceptor for a value. Everytime the function is acting as a setter, the interceptor notifies all observers (subscribers) of the value change.

Now let’s add a derived function (a.k.a. a dependent observable in KnockoutJS-speak) named savingsTargetPerMonth:

Note that ko.dependentObservable takes a function as a parameter as you would expect, but can also take a second optional parameter used to define the meaning of this inside the derived function. Typically we always pass the variable containing our viewModel.

Over time we can add more business logic to our sgs.mode.savingsgoal module.

5. Create the Savings Goal View Mediator

If you have not yet created the ViewMediators folder under the scripts folder, do that now. And then create a file named: sgs.mediator.savings-goal.js.
This is the module where we’ll place our data-binding logic as well as any code related to mediating access between the page, the savings goal view, and its view model.

This is where KnockoutJS is performing some heavy lifting behind the covers such as:

Setting observers on the actual HTML elements

Connecting these observers with the value models of the view model

Getting the initial value of each value model

Initializing each HTML element with that corresponding initial value

To make it possible to store and retrieve our view model later we’ll leverage the jQuery data API.
So let’s create 2 functions in the savings goal mediator (since it is acting as an intermediate between the browser, page, view and the model:

6. Link the Page and the View Mediator

Here is a diagram summarizing how we’ll be linking our parts:

Ok now we’re at a point to start testing our first draft, we just need to add a call to the overall page InitializeApplication function (located in scripts/application.js) to our savings goal createViewMediator function like so:

So now you should be able to load your index.html page in Firefox with the Firebug console on and watch the debug statement and finally our view displays with our initial data as well as the initial derived data for the “Savings Target Per Month” when you tab out of the amount or max number of months input fields:

7. Apply Data Formatting / Masking Business Rules

So far we have a nice simplistic example but if you build a solid app you will want to format and ensure our amounts are correct / valid / displayed according to conventional rules.
To my knowledge (having researched these types of libraries for a while), only library from PengoWorks has currency masking capabilities and will format the amount as you type it.
Since that library stopped being maintained in 2007, I started updating it (after checking with the original author, David Switzer) to make it work with current browsers). The resulting library is called CurrencyMask JS.
So let’s download the latest version to our ./scripts/vendor folder, and add a code snippet in our <head> LAB section:

Let’s add the mask instantiation snippet to the savings goal view model (at the end of the initializeViewModel function in sgs.model.savings-goal.js). Also note that we will need to perform the initialization of savingsGoalAmount based on pageSettings later on in the mediator – so here we’ll set the default value of savingsGoalAmountFormatted to an empty string:

And if we refresh the page and start typing 1500 in the amount it should format as we type along and prevent any other character input, ensuring the amount is valid.

But … we just introduced an issue (see the infamous NAN displayed in the Savings Target Per Month)!
Well, once formatted the savingsGoalAmount value model will now be a string containing currency and thousands delimiter characters.
So let’s recognize that semantic change by re-naming our savingsGoalAmount value model as savingsGoalAmountFormatted value model:

Now what we need to re-create a new savingsGoalAmount value model, and make it act as a two-way adapter to convert back and forth between formatted and unformatted values.
KnockoutJS can help us with that, using a “dependentObservable“. KnockoutJS also allows a hash to be passed to ko.dependentObservable. That hash can include the following key-value pairs:

owner – will specify the value of this

read – a function which can perform some post-processing and ultimately return the value of the observable

write – a function which can perform some pre-processing of a value and ultimately store it

So here is a skeleton of what the savingsGoalAmount value model would look like as a dependentObservable:

read: function () {
// Get the current formatted value model
// Important Note: Even though we don't use the formatted_amt variable
// in the rest of the function, we need to let KnockoutJS "know"
// that this closure has a dependency on savingsGoalAmountFormatted
// otherwise the closure will never be invoked on a read.
var formatted_amt = this.savingsGoalAmountFormatted();
// Unformat the value
var amt = this.savingsGoalAmountMask.strippedValue;
// Convert the result to a float
if (amt.length == 0) { amt = 0 };
return parseFloat(amt);
},

Now refreshing the index.html page should allow you to enter amounts and see the calculated value!

Here is a diagram summarizing how we restructured the various parts using the dependent observables and the mask:

I will leave the exercise for you dear reader to follow the same pattern for the “Savings Max Duration (In Months)” input field.
In that case the mask will be a little simpler since we need at most 2 digits.

8. Apply Custom Masking Rules

For custom masking needs, such as for example a phone number, social security id, special identifier,
I strongly recommend Josh Bush‘ Masked Input Plugin.

For dates I suggest using Masked Input together with jQuery Datepicker since the calendar makes it easy to select a date but does not provide masking features.

9. Applying Formatting Rules

When using our simple view you might have noticed that the “Savings Target Per Month” may show some numbers with many decimals. This is because the <span> element is data-bound to the savingsTargetPerMonth dependentObservable which returns a float. So we have two options:

Apply formatting to the float inside savingsTargetPerMonth

Or create another dependentObservable named savingsTargetPerMonthFormatted, in which we can apply the needed formatting logic. Then we would change the data binding for the <span> to use our new value model.

The cleanest approach is #2 since it also allows you in the future to build other dependentObservables on top of savingsTargetPerMonth. But if you don’t think you will need that ability then #1 will work and is very simple.

Approach 1 would require us to format the calculated value using the formatMoney function of Accounting.js like so:

Let’s refresh the index.html page and now when we enter $500 and 7 months, the max per month updates to dollar formatted two-decimal amount: $71.43!

10. Applying Visual Feedback Cues

When web pages require a round-trip to the server, the user waits and then sees the whole page refreshing, but in rich interactive apps since processing happens often very fast without a page refresh, we need to provide visual cues when changes occur. For quick feedback logic (e.g. not requiring an Ajax call or processing longer than a second) I recommend using a jQuery UI “effect”, such a temporary highlight using a soft color, like so:

Let’s refresh index.html, and whenever we see the xxx recalculate, the light green highlight of the result should fade in and out during our 3-second timeframe!

Overall Recap

So at this point we have built a reasonably solid foundation for our app even though it contains only one view. The architectural steps we took to decouple view, viewmodel, view mediator and the page will yield some benefits once we add continue adding features to our app (in part 3).

So What?

Many KnockoutJS tutorials focus on giving you the basics to run simple scenarios. My approach here although more “architected” is geared at building rich interactive apps made of multiple panels/views with solid interactions.

The modularization of our code base will also lend itself better to unit testing and even BDD testing using Javascript test frameworks like Jasmine and Jasmine-Species. They will allow us to write tests against our view models and to a certain degree some of the various Javascript modules.

We have focused on a one-view increment for the app but in Part 3 we will cover the following topics:

Actually we need because even though we don’t use the formatted_amt variable in the rest of the function, we need to let KnockoutJS “know” that this closure has a dependency on savingsGoalAmountFormatted otherwise the closure will never be invoked on a read.
This is definitely a bit tricky I agree but this is how KnockoutJS works.

Comment by techarch | October 22, 2011

this is just an awesome tutorial, especially for some one coming from a C++/Java enterprise application background. Thank you!

Comment by sat_dev | January 13, 2012

Thanks for this awesome tutorial.
I am facing an issue with hierarchy.
How should I model a structure like this Projects -> Project -> Ticket -> Task. Should I create a single model or there should be multiple?

ProjectList has Project Array, Project has Ticket Array and Ticket has Task array. In your sample I saw you are creating different models and binding them as per the sections of cshtml.

Here I have an outer foreach loop for projects, and rest all things are falling in the same loop. I cannot create multiple separate sections, then how do I bind it?

A single model will be too complicated.

Pl help..

Thanks,
Bhoomi

Comment by Bhoomi Kakaiya | January 16, 2012

Thanks Bhoomi!
I personally would recommend a different view model for each to maintain the logic separation. And you could have an overall view model for the app which could have the following value models:

You could include currentTicket in the Project view model – that's fine.
I would leave the responsibility to instantiate view models to the view mediator.

I would still recommend one view mediator for each view being bound to a specific view model. So if you have a view (e.g. ticket-view), I would have a corresponding view mediator to encapsulate all data-binding and various event handlers.
I have found that once an app becomes quite large, the modularization will pay off over time.

Comment by techarch | January 16, 2012

first of all let me thank u for this wonderful tutorial.. now we r also following this architecture in our project.

Comment by krk | January 17, 2012

Nice article – the only thing I'd take exception with is the use of the viewmediators.
I see many people draw the (false) parallel between inline data-binding and inline javascript or inline styles. The latter two are of course considered bad by most people with a lot of justification. However, the situation is not the same with in-line data-binding – in fact the opposite is true. With a mediator – now I have to simultaneously read two files to understand what is going on the in the view.

When defining any coding standard – the pros and cons should be considered – using a mediator here, seems to me to be more about blindly applying a standard that applies to something which looks similar without really thinking about why we are doing it. The only time this approach would be acceptable is if the view was self-standing without the data – the fact is that the binding is fundamentally part of the view and to introduce a separation between the view and the binding (as opposed to the view and the functionality), is counter-productive. Obviously we should separate the functionality, but separating the binding as well is a step too far.

Comment by Tony | March 15, 2012

Hi Tony, thanks for your feedback. I agree that using view mediators makes things more complex albeit more decoupled. And as you suggested everyone should do their homework and weighing pros and cons. If the app is very simple you can certainly opt for inline bindings. One area I have not really written about is the use of KnockoutJS for mobile apps (e.g. with jQuery Mobile and Phonegap (now Apache Cordova). But once you plan on making a mobile version of your app you will soon appreciate the flexibility of mixing and matching view models, views, and view mediators. You will most likely further breakdown your views and view mediators, and extending or modifying them as needed.

Comment by techarch | March 17, 2012

As some new to javascript, TDD etc , i like the structure you bring. What am missing is how you will have tested the code with jasmine.
is there a reason why you didn't include some specs?

Thanks

Comment by Corku | September 5, 2012

Some of the greatest tutorials which covers all the architectural ideas brilliant but yet simple. Thank you so much Phil for your effort. I'm yet to look at part 3 and 4. Once again thank you so much