Using knockout.js with the module pattern

The tutorials at http://learn.knockoutjs.com/ are awesome but the object literal style they are written in brings me back to nightmares of large Javascript applications I wrote before I read Douglas Crockfords book, Javascript: The Good Parts, and became a convert to the module pattern that he espouses in the book.

Part of my conversion to the module pattern was that allows for information hiding but probably a bigger part was just the style of the code. Over the years I learned to hate the multiple hundred line object definitions that were brittle because I left out a comma after a function definition or were crufty because I couldn’t reference the enclosing object. If you have been there you know what I’m talking about.

As I went through the tutorials I started hoping beyond hope that I could get the awesomeness of knockout.js but lose the horror of object literal functions. Once I was through all of them I started playing around and decided to rewrite the end result of the first tutorial using the module pattern. In case you haven’t gone through the tutorial first (you really should) here is the final template from the first tutorial:

Final template

<p>First name: <span data-bind="text: firstName"></span></p>
<p>Last name: <span data-bind="text: lastName"></span></p>

<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>

<p>Full name: <span data-bind="text: fullName"></span></p>

<button data-bind="click: capitalizeLastName">Go caps</button>

and here is the final code using their object literal style:

Final code using an object literal style

var viewModel = {
    firstName: ko.observable("Bert"),
    lastName: ko.observable("Bertington"), 

    capitalizeLastName: function() {
        var currentVal = this.lastName();
        this.lastName(currentVal.toUpperCase());
    }
};

viewModel.fullName = ko.dependentObservable(function() {
    return this.firstName() + " " + this.lastName();
}, viewModel);

ko.applyBindings(viewModel);

Maybe its just a matter of style, and you might not have a problem with the above code, but having to define the dependent observer outside of the object literal because it can’t reference the object bugs me, as does having to expend mental energy to make sure this is really the viewModel object because its being passed as the second parameter in the ko.dependentObservable function call.

Converting the code to the module pattern lets me define both the observables and the dependent observables in the same function and use a private function to implement behaviors of the view module. It also allows me to encapsulate the view model into a function so I can move it to an external include file and call it against an arbitrary person object. For a simple example like this it seems like overkill but when you start building large single page Javascript applications encapsulating data and methods is a guard against insanity. With all that in mind here is the code converted to the module pattern:

Final code using the Module Pattern

var PersonViewModel = function (person) {
	var firstName = ko.observable(person.firstName || ""),
		lastName = ko.observable(person.lastName || ""),
		fullName = ko.dependentObservable(getFullName);

	return {
		firstName: firstName,
		lastName: lastName,
		fullName: fullName,
		capitalizeLastName: capitalizeLastName
	}

	function getFullName() {
		return firstName() + " " + lastName()
	}

	function capitalizeLastName() {
		lastName(lastName().toUpperCase());
    }
};

ko.applyBindings(PersonViewModel({"firstName": "Doug", "lastName": "Martin"}));

TL/DR: knockout.js is awesome. Doug doesn’t like object literal function construction. The module pattern works fine with knockout.js.

One comment

Leave a comment