Barbarian Meets Knockout.js: Introduction, or How to Enrich your HTML Views with Unparagoned User Experience
The “barbarian meets” series are a collection of articles that intend to introduce and explain useful libraries, frameworks, tools and technologies in simple and straightforward terms. These new series will focus on Knockout.js, the popular JavaScript MVVM library
Have you ever done any XAML development? Have you ever wondered or considered how cool it would be to use XAML-style data bindings and MVVM on the web? How awesome to get that level of rich user experience and separation of concerns? Well, that is what Knockout.js is all about.
And now that I have painted a clear picture in your mind .NET developer, and alienated you non .NET developer for using a completely useless simile I will go with the more accurate, yet less sensational introduction:
Knockout.js is an outstanding JavaScript library that lets you create super rich user experiences in the web by providing an easy and seamless way to sync your HTML views with your underlying data. Its core strengths: declarative two-way data bindings and a full-blown templating engine.
I understand… words are just words… you want to see some code! Behold!!!
<!-- Declarative bindings let you associate DOM elements with the underlying data -->
<section class="container">
<h1>Register!</h1>
<form>
<!-- see the declarative bindings as data-bind attributes below. They bind these input elements to the underlying ViewModel -->
<label>Name: </label><input data-bind="value: name, valueUpdate: 'afterkeydown'" type="text"/>
<label>E-mail: </label><input data-bind="value: email, valueUpdate: 'afterkeydown'" type="text"/>
<label>Password: </label><input data-bind="value: password, valueUpdate: 'afterkeydown'" type="password" />
<label>Repeat Password: </label><input data-bind="value: repeatPassword, valueUpdate: 'afterkeydown'" type="password" />
<button type="submit" data-bind="enable: isValid">Go!</button>
</form>
<!-- when the user edits the form, the text in these spans is updated automatically -->
<p>
Thank you for signing up <span data-bind="text: name"></span>! We will send you a confirmation e-mail to <span data-bind="text: email"></span> :)
</p>
</section>
<script>
// Model (this is the original data)
var user = {
"name": "Conan",
"password": "Crom1234!",
"email": "[email protected]"
};
// View Model (this is a representation of the data for this particular view/webpage)
var CharacterViewModel = function () {
var self = this;
self.name = ko.observable(user.name);
self.email = ko.observable(user.email);
self.password = ko.observable(user.password);
self.repeatPassword = ko.observable("");
self.isValid = ko.computed(function(){
return self.name() && self.email() && self.password() == self.repeatPassword();
});
};
// Start knockout and kick bindings!
ko.applyBindings(new CharacterViewModel());
</script>
Check out this Pen!
Ok… now that you have had a little taste of Knockout.js we can start with Knockout.js 101.
Barbarian Meets Knockout
- Introduction to Knockout.js
- Knockout.js Observables
- Knockout.js Computed Observables
- Introduction to Knockout.js Observable Arrays
- Knockout.js Observable Arrays in Knockout 3.0
- Knockout.js Bindings
- Knockout.js Templating Engine
- Extending Knockout.js with Custom Bindings
- Inside the Source Code
- Scaling Knockout.js
- Knockout.js and SPAs (Single Page Applications)
- Persisting Data When Using Knockout.js in the Front End
- Using Knockout in an unobstrusive fashion
- The Bonus Chapters
A Note About the MVVM (Model-View-ViewModel) Design Pattern
Before I start with knockout, I would like to do a brief aside to agree on and clarify some concepts. The natural architecture that emerges when using Knockout in your front-end is MVVM (Model-View-ViewModel), one of the MV patterns whose main purpose is the separation of corcerns. Ideally, the View would be solely in charge of presentation and would represent the information exposed by the ViewModel. The ViewModel would gather, aggregate and compose a part of the model and would adapt it to a particular view, effectively isolating the presentation layer from the domain model. Finally, the Model would contain all the entities and logic of any particular business domain your application lives in. In this context, the view would know about the view model, but not about the model, in turn the view model would be aware of the model and be oblivious about the view, and finally the model couldn’t care less about both view and view model. Hence effectively achieving both a logic and a physical separation of concerns.
With Knockout.js, when I talk about View I will be referring to your HTML/DOM, when I talk about model I will refer to the representation of your domain model in the front-end, normally a JSON object, and when I talk about ViewModel I will refer to the JavaScript construct that exposes and adapts the model to the view. From my experience with knockout.js, the model side in the front-end doesn’t play a part as important as in traditional MVVM and is mostly relegated to a temporary representation of the actual model that exists somewhere in the back-end.
Generally, the way to achieve loose coupling between View and ViewModel is through the use of data binding, and that’s what Knockout.js excels at.
Knockout’s Data Bindings
Knockout data binding model relies on two cornerstones: Declarative data bindings and observables.
Declarative Data Bindings
The first step for binding data to DOM elements with Knockout.js consists in specifying which data is going to be bound to what parts of your HTML document in a declarative fashion. Knockout.js takes advantage of HTML5 custom data attributes and uses the data-bind
attribute to specify the source of a binding. You can, for instance, bind text:
<!-- this binding -->
<span data-bind="text: name"></span>
<!-- would produce -->
<span data-bind="text: name">Jaime</span>
or CSS classes:
<!-- this binding -->
<tr data-bind="css: {highlight : isSelected}"></tr>
<!-- would produce when the row is selected-->
<tr class="highlight" data-bind="css: {highlight : isSelected}">Jaime</tr>
or events:
<!-- this binding would call the increaseQuantity function when the button is clicked -->
<button data-bind="click: increaseQuantity">+</tr>
Knockout.js provides a considerable number of built-in bindings that I will focus on in the third article of these series. In the meantine, if you cannot wait to find out, feel free to browse the Knockout.js Documentation.
Observables
The other side that makes all this data-binding business work are what we know as observables. Observables are objects that notify your view when changes occur in the ViewModel, ensuring in that way, that your View and ViewModel remain in sync. We can easily declare a ViewModel property as observable as illustrated in the code example below:
// An example viewModel
var viewModel = {
name: ko.observable('Jaime'),
age: ko.observable(29),
}
// Observables are functions, so you set an observable like:
viewModel.name('John')
// You can also use method chaining to set several values:
viewModel.name('Justin').age(22)
// Conversely, you read the value of an observable like this:
var name = viewModel.name()
Knockout.js provides other two additional types of observables: computed observables, observables whose value is calculated from other observables, and observable arrays, which monitor changes in collections of things (like an ObservableCollection would). We will dive into observables in the second article of these series, but, again, if you feel impatience, go ahead and check out the Knockout.js Documentation.
Note: Bear in mind that you can always bind DOM elements to pure JavaScript objects but you will not get the benefits of two way data binding. It will be a one-time binding.
The Course Examples
I thought that, to spice things up, I could keep the same theme throughout the series when preparing the different code samples. So…TaDa!! Blood and Steel the digital pen and paper RPG!!!!
Of course this game is ficticious and will never, ever exist, but it is fun for illustrative purposes nonetheless XD
So here is the first example (if we don’t count the mini registration form). A simple character sheet:
Check out this Pen!
Feel free to play around :). Changes within the input
elements should automatically update the description below.
Other Awesome Resources
- Knockout.js Documentation
- Learn Knockout.js
- Knockout.js Live Examples
- Building HTML5 and JavaScript Apps with MVVM and Knockout at Pluralsight
- Stackoverflow knockout tag
- knockmeout.net (Ryan Niemeyer’s blog)
- Tekpub Practical Knockout.js
- Tekpub Refactoring Knockout
- Barbarian Meets Coding Knockout.js Wiki
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.