Subscribe to all changes of an entire Knockout ViewModel

Knockout is amazing. It is fast and intuitive. I use the subscribe function a lot, but I found myself lacking a general subscribe that allows me to track the changes of an entire ViewModel, so I created one myself that even supports unsubscribe and throttling.

The basic idea

So what are we going to do? Given a ViewModel, we'll:

  • Find all observable properties
  • Subscribe to those properties
  • Inspect the value of each observable property and do the same: find, subscribe and inspect.

We'll extend on the ko variable, so we'll get the following new features:

  • To subscribe a model: ko.subscribe(vm, fn, 100);
  • To unsubscribe a model: ko.unsubscribe(vm, fn);

So let's dive in!

First things first: LoDash

Lo-Dash is a low-level utility library that implements common operations. It was created as a fork of the Underscore project. Unlike most libraries, Lo-Dash eschews almost all native iteration methods in favor of simplified loops, resulting in tight, lean code (read more). It makes code faster and more readable. I use it for array loops and to implement the throttling feature.

Tha code

A while back I wrote a blog on Automatic Knockout model persistence with Amplify. I'll be using the same method for looping through the properties of a model.

(function () {

	//stores the subscriptions
	var subscriptions = [];

	//maintains a unique identifier 
	var id = 0;

	ko.subscribe = function (vm, fnOnChange, throttle) {

		var myId = ++id;

		//store subscription - add throttle
			id: myId,
			change: _.throttle(function () {
			}, throttle)

		//subscripe model with id.
		_subscribe(vm, myId)

	ko.unsubscribe = function (vm, fnOnChange) {
		_.remove(subscriptions, function (item) {
			return item.vm == vm && item.change == fnOnChange;

	function _subscribe(vm, id) {

		if (_.isArray(vm)) {

			//loop through array values and subscribe to each item
			for (var i = 0; i < vm.length; i++) {
				_subscribe(vm[i], id);
		else {

			//prevent double subscriptions by checking
			//a 'magic' property:
			var subscriberId = '_ko_subscr_' + id;

			if (_.isUndefined(vm[subscriberId])) {

				vm[subscriberId] = true;

				//subscribe to each observable
				for (var n in vm) {

					var observable = vm[n];

					if (ko.isObservable(observable) && !ko.isComputed(observable)) {

						observable.subscribe(function (newValue) {

							//subscribe the new observable value
							_subscribe(newValue, id);

							//fire event, because something just changed

						//subscribe to current value stored by observable
						var currentValue = observable();
						_subscribe(currentValue, id);

	function fire(id) {
		_.forEach(subscriptions, function (item) {
			if ( == id) {


ko.isComputed = function (instance) {
	if ((instance === null) || (instance === undefined) || (instance.__ko_proto__ === undefined)) {
		return false;

	if (instance.__ko_proto__ === ko.dependentObservable) {
		return true;

	// Walk the prototype chain
	return ko.isComputed(instance.__ko_proto__);

So basically that's it.


I've created a Random Greeting demo in JsFiddle, so you can see this code in action.