Barbaric Monthly is my attempt at building/improving a coding project per month so that I can experiment with old and new technologies, learn ad infinitum, remain excited about the craft and nurture my passion for software development. This Barbaric Monthly is about practicing knockout.js building a web-based Pomodoro technique client: il Pomodoro.
Hello my fellow coders! Soon I’ll be going on vacation to a remote and undisclosed location for the next three weeks! Unfortunately I won’t have access to these beloved devices that we call computers, and least of all to the internetz, that’s why I thought it would be nice to write one last blog post before I step into the wilderness, perhaps, never to return - one never knows what prowls within the unknown :).
It has been a while since the last barbaric monthly since I have being mainly focusing in studying and getting my WebDev fu up to speed for my current job at medius. Although I haven’t really been working solely on any project in particular, I have tinkered on an off with il Pomodoro, a simple web based Pomodoro technique app written with knockout.js.
The project is in a very early stage providing the most basic functionality within the pomodoro technique: creating tasks, dividing them into pomodoros and a pomodoro timer. Check it out at www.barbarianmeetscoding.com/iPomodoro and GitHub.
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
Updated June 11th 2013 from the awesome comments by Maciej Makowski
I already used up the sensational introduction in the first blog post of these series so unfortunately I see myself forced to go straight down to business this time xD. In the last installment of these series we gave a short introduction to Knockout.js, what it is, why should you care and how to get started. In this blog post I will focus in one of the pillars of Knockout, the concept of observables, JavaScript objects that have the ability to notify others when they have been changed. Let’s get started.
Persisting Data When Using Knockout.js in the Front End
Using Knockout in an unobstrusive fashion
The Bonus Chapters
Introducing the Example: The Pen&Paper RPG Inventory Screen
For this particular chapter, I have created this teeny tiny example that represents an inventory screen of our Pen&Paper RPG: Blood & Steel!! (I just started roaring while I was writing blood & steel - true story). Within it, the player will be able to drop items from the inventory freeing himself from unnecessary weight and the overstrained weakening status. Through the next sections, I will go disecting the example as I explain the concept of observables, and I will continue using it even in later chapters when I delve into computed observables and observable arrays. Here it is:
Observables are JavaScript objects - to be more accurate they are functions as we will see later, but functions are objects in JavaScript so… well… :) - that have the ability to notify others when they have been changed. Thus allowing DOM elements to be updated and other programming constructs to perform operations in response to these changes. We create observables by using the ko.observable function:
// Modelvar player ={name:"Kull",...}// ViewModelvarPlayerViewModel=function(){var self =this;
self.name = ko.observable(player.name);// Initialize the value of the observable to the name of the player...};
We then can read or update the observable easily by using a normal function notation:
var aPlayerViewModel =newPlayerViewModel()var playerName = aPlayerViewModel.name()// read
aPlayerViewModel.name('John Doe')//write
aPlayerViewModel
.name('John Doe').characterClass('Barbarian').race('Cimmenrian')// observables support function chaining
Whenever we change the value of the observable (name in this example), whichever construct that is listening will be notified. Notice, for example, how when you click on the Change Player Name Via Code in the example, the DOM element that is bound to the name observable is updated and reflects John Doe instead of Kull.
<divclass="sidebar"><!-- this span is bound to the name property of the underlying view model --><h2><spandata-bind="text: name"></span>...</h2>
...
</div><!-- this button is bound to the changeName function, when clicked it will execute it --><btnclass="btn btn-block"data-bind="click: changeName">Change Player Name Via Code</btn>
You are not limited to use declarative bindings to bind DOM elements to your view Models. In addition to this standard way of binding, Knockout also provides support for explicitely subscribing to changes in an observable by using the subscribe method. In our example, I have written a simple mechanism to track changes in our ViewModel and activate a Save button.
varPlayerViewModel=function(){...// change trancking system
self.hasChanged = ko.observable(false);// this function below will be executed when the name is changed
self.name.subscribe(function(newValue){
self.hasChanged(true)});
self.saveChanges=function(){// save changes
self.hasChanged(false);}
Explicitly Triggering the Evaluation of Observables with ValueHasMutated
In certain scenarios, you will want to be able to trigger the evaluation of an observable, computed or observable array explicitly. You can achieve this by using the valueHasMutated function for any observable. Ryan Niemeyer has a great example on jsFiddle where he uses the valueHasMutated function to round a decimal input.
What Happens if I Do Not Use Observables?
The most simple binding scenario is that in which you bind your DOM elements to a vanilla JavaScript object. There is nothing wrong with this, knockout will pick those values and reflect them in your view. However, bear in mind that you will effectively have a one way, one time binding; that is, the value shown in your view will be read-only and if changed in the ViewModel, it will not be updated in the view.
Improving Knockout Readability with the Knockout-ES5 Plugin
At the point of this writing, Steven Sanderson has created a new plugin for knockout: knockout-es5. This new plugin allows you to abandon the function notation for reading/writing values from/to an observable in favor of using a more conventional and straightforward way of setting variables/properties:
// Let's say we have a simple system to spoil the player's food over time// in classic knockout we would writevar latestConsumable =this.consumables()[this.consumables().length -1]// Read a value
latestConsumable.isSpoiled(true)// Write a value// whereas in knockout-es5 we would writevar latestConsumable =this.consumables[this.consumables.length -1]// Read a value
latestConsumable.isSpoiled =true// Write a value
As a final note on observables, I thought it would be both interesting and revealing to take a look at the actual Knockout.js source code. You can find the source code for observables under src/subscribables/observable.js. I have just selected the most juicy bits and left it untouched because it is pristine clear:
ko.observable=function(initialValue){var _latestValue = initialValue
functionobservable(){if(arguments.length >0){// Write// Ignore writes if the value hasn't changedif(!observable['equalityComparer']||!observable['equalityComparer'](_latestValue, arguments[0])){
observable.valueWillMutate()
_latestValue = arguments[0]if(DEBUG) observable._latestValue = _latestValue
observable.valueHasMutated()}returnthis// Permits chained assignments}else{// Read
ko.dependencyDetection.registerDependency(observable)// The caller only needs to be notified of changes if they did a "read" operationreturn _latestValue
}}if(DEBUG) observable._latestValue = _latestValue
ko.subscribable.call(observable)
observable.peek=function(){return _latestValue
}
observable.valueHasMutated=function(){
observable['notifySubscribers'](_latestValue)}
observable.valueWillMutate=function(){
observable['notifySubscribers'](_latestValue,'beforeChange')}
ko.utils.extend(observable, ko.observable['fn'])
ko.exportProperty(observable,'peek', observable.peek)
ko.exportProperty(observable,'valueHasMutated', observable.valueHasMutated)
ko.exportProperty(observable,'valueWillMutate', observable.valueWillMutate)return observable
}
Gotcha’s and Good Things to Know About Observables
Updated June 11th 2013
Knockout.js Always Notifies Observables When They Are Set To Objects
Before I mentioned how observables notify their subscribers when they are changed. Well… That is not entirely true. In reality, an observable will notify its subscribers:
when its value changes for primitive types (number, boolean, string and undefined) or,
always for object types.
See the implementation of equalityComparer and notice how it always returns false when the old value is an object:
// src/subscribables/observable.js
ko.observable['fn']={equalityComparer:functionvaluesArePrimitiveAndEqual(a, b){var oldValueIsPrimitive = a ===null||typeof a in primitiveTypes
return oldValueIsPrimitive ? a === b :false},}
Notice also the following test that documents that behavior:
// spec/observableBehaviors.jsit('Should notify subscribers of a change when an object value is written, even if it is identical to the old value',function(){// Because we can't tell whether something further down the object graph has changed, we regard// all objects as new values. To override this, set an "equalityComparer" callbackvar constantObject ={}var instance =newko.observable(constantObject)var notifiedValues =[]
instance.subscribe(notifiedValues.push, notifiedValues)instance(constantObject)expect(notifiedValues).toEqual([constantObject])})
If this behavior is not to your liking, know that you can provide your own custom implementation to equalityComparer.
Don’t Forget To Obliterate Your Manual Subscriptions
In certain scenarios (see example by Maciej below), a manual subscription will prevent your objects from being garbage collected, and thus create memory leaks (something that you are going to particularly want to avoid when writing SPAs):
functionA(){var self =this
self.observable1 = ko.observable()}functionB(a){var self =this
self.observable2 = ko.observable()
a.observable1.subscribe(functionsync(newValue){// this closure hold reference to "self" but is stored in "a.observable1"// so as long as "a" cannot be garbage collected, "self" won't be as well
self.observable2(newValue)})}
It is thus recommended to dispose these subscriptions when you no longer need them (again Maciej’s example):
functionA(){var self =this
self.observable1 = ko.observable()}functionB(a){var self =this
self.observable2 = ko.observable()
self.mySubscription = a.observable1.subscribe(functionsync(newValue){// this closure hold reference to "self" but is stored in "a.observable1"// so as long as "a" cannot be garbage collected, "self" won't be as well
self.observable2(newValue)})
self.dispose=function(){// this needs to be called when instance of B is no longer// needed
self.mySubscription.dispose()}}
Finally, this is what happens when you subscribe to an observable (I have removed some code for the sake of simplicity):
// src/subscribables/subscribables.js
ko.subscribable=function(){this._subscriptions ={};...}
ko.subscribable['fn']={subscribe:function(callback, callbackTarget,/*change*/ event){...var subscription =newko.subscription(this, boundCallback,function(){// This callback is called when disposing a subscription
ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);}.bind(this));if(!this._subscriptions[event])this._subscriptions[event]=[];this._subscriptions[event].push(subscription);return subscription;},...}
ko.subscription.prototype.dispose=function(){this.isDisposed =true;this.disposeCallback();};
So! That was about it for Observables. I hope you now have a much clearer idea of what observables are, how they work and how you can take the most advantage of them. In the next chapter of these series I will be discussing computed observables. Have a good weekend! :)
I would say I was pretty proficient writing and editing code. I have always been a pretty fast typer since I can recall (~100 wpm), albeit with my weird own style of typing (Home row what-is-that?). I am also quite good with ReSharper, which really gives me wings when doing macro-application-aware editing or navigating inside my solution and a great sense of flow when doing TDD. I would say I was pretty proficient writing and editing code, that was once, that is…
Two weeks ago I started using proper typing skills, two weeks ago I started using vim and the vsVim plugin for Visual Studio and maaaan it’s been tough :). The promise of ultimate productivity that we programmers so much long for, that same promise of a seamless interface between our brains and the editor where our thoughts become code, pushed me once more into the abyss… but I am alive and kicking, and here is my story… xD
The first day typing with the home row I dropped to a staggering 10wpm, hell yeah!. I have never felt in my own skin how detrimental subpar typing skills can be to programming (although I understand it is freaking obvious): Coding wasn’t even fun anymore. It has gotten better though, I type now at a steady ~60wpm, and I enjoyed a lot going through the process and reflecting about why the keys are layed out the way they are. Every day is a new wonder XD, I can recall and even see myself talking to Malin about typing… go figure.
And vim; I think I have tried learning vim twice before. I am starting to think that there is a time for every teaching, for every lesson to be learned, sometimes one is just not ready. This time it appears I was, I totally understood, I got it. The first experience opening vim was still scary though, particularly with how spoiled I am today in regards to aesthetics, but then I got it “You are supposed to customize it, Doh!“. I have started using both vim and vsVim and I like it, I do feel like a code surgeon, precise, and I feel free, navigating through the code is a breeze.
The funniest thing of all, that which tells me that vim does indeed work, is that I am trying to vim my way through everything: when typing an email on Gmail or Outlook, when writing a wiki entry on Confluence, or a description in Jira… :)
Well, that’s all for now. I’ll keep you updated on how this whole foolishness ends up xD. Have a nice weekend!!
And Some Interesting vim Resources for the Initiated and Non Initiated
The inspiration corner is the space where I share talks, speeches, videos, articles, posts, whatever that helps me keep my motivation, energy and passion fresh, and what I hope will serve you as well as it does me.
I like to see myself like a beam of positiveness, an inexhaustible source of energy and unbending willpower. Sometimes, however, I get tired… veeery tired. In those moments, I find it is great to recharge with inspiring tales and stories of others. Like this one, the story of minecraft and mojang.