3 Ways to Deal with SFOUC in KnockoutJS

What is SFOUC?

A Sudden Flash Of Unstyled Content, or SFOUC, refers to that irritating few milliseconds between when your web page loads and when all of your dynamic content pops into place.

The reason for this annoying phenomenon is that your HTML is being rendered a split second before your CSS & JavaScript files have finished downloading and running.  The un-augmented HTML sits there just long enough to catch the eye of your user, and then is whisked away as soon as all the lovely dynamic content is ready to replace it.

I’ve found that this is particularly evident when working with KnockoutJS because generally the last line of your startup code is ko.applyBindings(viewModel), and until you bind the view model you always see the unstyled content.

So how can we stop this menace?

Option 1: The “Classic” Approach

KnockoutJS is just a library on top of JavaScript so there is no reason why we can’t use the same approach as is suggested for non-Knockout apps.

There are a few flavours to this, but as a general solution:

  1. Add a class to the body element (e.g. no-js)
  2. Add a class to the dynamic content (e.g. dynamic-content)
  3. Add a style that hides dynamic-content within no-js

    .no-js .dynamic-content { display: none; }
    
  4. Add some JavaScript to remove the no-js class from the body once everything is loaded

    document.body.className = 
        document.body.className.replace("no-js", "");
    

This will do the job quite nicely, but still relies on the CSS loading quickly enough to hide the dynamic content before anyone notices.

Option 2: The “Visible” Approach

If the idea is to reduce the amount of time the basic HTML is visible then the fastest place to put the “don’t show this” instruction is in the HTML itself – using a style="display:none" tag.

The problem with this approach is that you then have to to go through and remove all of those styles once your JavaScript is ready to run; this is where the visible binding can help us out.

Under the covers, the visible binding simply sets the display style to none or to "" (i.e. not set) so we can use this to automatically remove the style tags created above:

<div style="display:none" data-bind="visible: true"> </div>
<!-- or -->
<div style="display:none" data-bind="visible: $data"> </div>

The first of these examples will display the div as soon as Knockout is bound; the second will display as soon as the current context has a truthy value.

Option 3: The “Make-Everything-A-Template” Approach

Instead of trying to hide rendered HTML content until we’re ready, what if we just stopped rendering it all together?  If we put all of our dynamic content inside script tags (which obviously won’t be rendered by the browser) then we can use the template binding to render the content from inside the script tags in the context of a view model.

<div data-bind="template: 'dynamic-content'">
    <!-- will appear empty on page load -->
</div>

<script id="dynamic-content" type="text/html">
    <h1>This will be rendered by Knockout</h1>
</script>

This makes for slightly more verbose markup than the other approaches but we can improve on this by switching to the containerless syntax:

<!-- ko template: "dynamic-content" --><!-- /ko -->
<script id="dynamic-content" type="text/html">
    <h1>This will be rendered by Knockout</h1>
</script>

A Note about Progressive Enhancement

Obviously if you want to employ progressive enhancement then these approaches will not work for you – they work by hiding the content until it is ready to be rendered.  If you are using progressive enhancement then I’m going to assume that the original HTML renders nicely anyway and that you don’t care about the SFOUC problem!

Advertisements

Handling ‘this’ in ko.command

Update: this feature is now available as part of the ko.plus library available on GitHub and NuGet!


The problem of context – the this value – in JavaScript is one that seems to keep causing problems.  Languages with similar syntax (C#, Java) do not allow the developer to alter the value of this and so people don’t always expect that it can change.

JavaScript likes to be different though.

I don’t want to get into too much detail on how this behaves – there are already more than enough articles out there that cover the topic to a greater depth than I could (e.g. Scope in Javascript); instead, this is a post about how I have worked around the issue in my ko.command library.

Problematic Command Context

Take the following simple example usage of the command library.

function ViewModel() {
    this.value = ko.observable(123);
    this.increment = ko.command(function() {
        this.value(this.value()+1);
    });
}

var viewModel = new ViewModel();
viewModel.increment();
//viewModel.value() => 124

The increment command adds 1 to the value of an observable property on the same view model; everything is working so far, but what if we move the implementation of the command action onto the prototype?

function ViewModel() {
    this.value = ko.observable(123);
    this.increment = ko.command(this._increment);
}

ViewModel.prototype._increment = function() {
    this.value(this.value()+1);
}

We might expect this to behave in the same way as before, but now when we call increment we get an error that, after a little investigation, we can see is because the value of this within the _increment function is not set to the view model.

Now It (mostly) Just Works

This behaviour was actually down to a design decision in the earlier version of the library to set the context of the various callbacks to the command itself; only recently has this started to cause problems that have prompted me to fix it.

The updated behaviour (available for download from Github) now endeavours to “just work” wherever possible.  This means that in the scenario above there are no code changes required to use the prototype implementation.

To be specific, the command action will always be invoked in the context from which the command was called which should (in most cases) behave in a way that seems to make sense.

There are some specific scenarios where a little more work is needed though.

CanExecute Function

The canExecute property on any ko.command instance is currently implemented as a computed observable, and as explained in the Knockout documentation, computed observables can be a little tricky when dealing with the context.

The behaviour does make sense when you consider the cause: computed observables will be re-evaluated whenever a dependent observable changes, so there is no way for them to (automatically) guarantee the context in which it will be invoked.

It is, however, possible to explicitly specify a context for a computed observable, so ko.command has been extended to mimic this implementation:

function ViewModel() {
    this.value = ko.observable(123);
    this.increment = ko.command({
        context: this,
        action: this._increment,
        canExecute: this.somethingThatReliesOnScope
    });
}

In this example the value of this when running the canExecute function will always be set to the current instance of ViewModel.

Note: explicitly setting the context in this way will also override the default behaviour when invoking commands, so use it carefully!

Asynchronously-Invoked Callbacks

The callbacks to an asynchronous command can be attached using the done/fail/always functions and are invoked once the promise returned by the action has completed.

function ViewModel() {
    this.value = ko.observable(123);
    this.incrementAsync = ko.command(function() {
        var promise = $.Deferred();
        promise.resolve();
        return promise.promise();
    }).done(this._increment);
}

But in what context will they be executed?

This scenario is a little more complicated because the promise implementation itself is able to specify the context in which callbacks should be invoked (in jQuery this is achieved using resolveWith).  In this case we have 3 choices:

  1. Do nothing.  Leave the context for the callback as whatever is set by the promise
  2. Replace the promise context with the context from the command
  3. Replace the promise context, but only if it has been explicitly specified.

For the time being I decided to leave the behaviour unchanged as it feels like changing it – forcing the context back to the command context – would be breaking the expected behaviour of whoever has explicitly (or implicitly) set the context of the callback.

Editable Object Graphs in Knockout

Update: this feature is now available as part of the ko.plus library available on GitHub and NuGet!


A little while back I wrote a post about making editable fields in knockout that allow you to enter an “editing” mode and then either persist or discard any changes made during the edit.

This works by storing a copy of the current value when beginEdit is called, then optionally restoring it on cancelEdit.

This is useful for individual fields but generally you want to make entire view models editable, so how can we extend this to work for more complex scenarios?

Extending to Entire Objects

The first step here is to be able to call beginEdit on an entire object instead of each individual field.  Imagine we have the following object:

var ViewModel = function() {
    this.property1 = ko.editable("initial value");
    this.property2 = ko.editable(123);
};

We should be able to call new ViewModel().beginEdit() and have both properties enter edit mode.  We should also have a new isEditing property on the view model itself to indicate global state.

var ViewModel = function() {
    //invoke 'makeEditable' to make the entire object editable
    ko.editable.makeEditable(this);

    this.property1 = ko.editable("initial value");
    this.property2 = ko.editable(123);
};

var viewModel = new ViewModel();
viewModel.beginEdit();
//viewModel.isEditing() === true
//viewModel.property1.isEditing() === true
//etc

viewModel.cancelEdit();
//viewModel.isEditing() === false
//viewModel.property1.isEditing() === false
//etc

Easy enough to describe, but how do we make it work?

First off, we need to append some wrapper methods and an isEditing flag to the target of the makeEditable function:

ko.editable.makeEditable = function (target) {
	//observable flag to hold global object state
	target.isEditing = ko.observable(false);

	target.beginEdit = function () {
		//...
	};

	target.endEdit = function () {
		//...
	};

	target.cancelEdit = function () {
		//...
	};
};

Next, we need each of those functions to do 2 things:

  1. Iterate through all of the editable properties on target and invoke the same method on each
  2. Update the target.isEditing flag appropriately

As number 1 will be pretty much identical for each of the functions, let’s create a helper function to iterate through the editable properties and avoid repeating ourselves (remember, DRY).

var forEachEditableProperty = function (target, action) {
	for (var prop in target) {
		if (target.hasOwnProperty(prop)) {
			var value = target[prop];

			//is the property editable?
			if (value && value.isEditing) {
				action(value);
			}
		}
	}
};

This function iterates through each property on the target object and, if that property has an isEditing flag (i.e. is editable), it will invoke the specified action.  Using this, our 3 functions in makeEditable become…

target.beginEdit = function () {
	forEachEditableProperty(target, function (prop) { prop.beginEdit(); });
	target.isEditing(true);
};

target.endEdit = function () {
	forEachEditableProperty(target, function (prop) { prop.endEdit(); });
	target.isEditing(false);
};

target.cancelEdit = function () {
	forEachEditableProperty(target, function (prop) { prop.cancelEdit(); });
	target.isEditing(false);
};

That’s all we need to do in order to support the immediate children of our current view model, but what about complex object graphs?

Extending to Complex Object Graphs

Imagine that we have the following view model that contains an editable child property and an array of editable children.

var ChildViewModel = function () { /* some editable object */ };

var ViewModel = function () {
    ko.editable.makeEditable(this);
    this.property1 = ko.editable("initial value");

    //editable child property
    this.child = new ChildViewModel();

    //array of editable children
    this.children = ko.observableArray([
        new ChildViewModel(),
        new ChildViewModel()
    ]);
};

Ideally we would want the beginEdit method on the parent view model to call beginEdit on all of the children, both in properties and in arrays.

Our existing implementation will already take care of the this.child property – if it’s editable then it will have an isEditing flag, so will be considered to be editable by forEachEditableProperty – but we will need to add some special handling for the array.

var forEachEditableProperty = function (target, action) {
	for (var prop in target) {
		if (target.hasOwnProperty(prop)) {
			//unwrap the value to support observable arrays and properties
			var value = ko.utils.unwrapObservable(target[prop]);

			//direct editables
			if (value && value.isEditing) {
				action(value);
			}

			//editables in arrays
			if (value && value.length) {
				for (var i = 0; i < value.length; i++) {
					if (value[i] && value[i].isEditing) {
						action(value[i]);
					}
				}
			}
		}
	}
};

We are making 2 changes here:

  1. We are unwrapping the property value using ko.utils.unwrapObservable.  This allows us to support editable objects that are in observable arrays and properties.
  2. We are checking the unwrapped value to see if it has a length property, and are iterating through if we find one. This allows us to support arrays (and observable arrays) containing editable children.

This recurses nicely over child objects that themselves have editable children, so this is in fact all we need to do to support complex object graphs. 

You can see a working example here and you can find the source code along with unit tests on GitHub.

Fallback Images with Knockout

After a busy few weeks at work I’ve finally managed to spend some time on knockout development again, and today I found a nice solution to a problem with data-bound images.

In my example I had a list of contacts that were being displayed on the page, and each contact had a URL linking to their profile image.

{
	Id: 1,
	FirstName: "Steve",
	LastName: "Greatrex",
	ProfileImage: "/some/image.jpg"
}

The binding to display the image is initially pretty simple – I can use the attr binding to set the src property on the img element using the vanilla knockout library.

<img data-bind="attr: { src: ProfileImage }" />

Simple enough, right?

Complications

Unfortunately some of my contacts don’t have a ProfileImage property.  Even worse, some of them do have a ProfileImage but it points to a non-existant image.

If I use the attr binding as above then I get an unpleasant looking “missing image” icon…

image

…when what I really want to do is use a placeholder image instead.

The img binding

To resolve this problem I created a new custom binding named img.  This expects a parameter containing an observable src property for the image URL, and either a hard-coded or an observable fallback URL to be used in case of null URLs or errors.

<img data-bind="img: { src: ProfileImage, fallback: '/images/generic-profile.png' }" />

The binding itself is nothing complicated.  As with all custom bindings you can optionally specify an update and an init handler that are called when the value changes and when the binding is initialised respectively.

For this binding, the update handler needs to check the value of both the src and fallback properties, then set the src attribute on the img to whichever value is appropriate.

The only thing that the init function needs to handle is the scenario where the image fails to load (using jQuery.error).

ko.bindingHandlers.img = {
    update: function (element, valueAccessor) {
        //grab the value of the parameters, making sure to unwrap anything that could be observable
        var value    = ko.utils.unwrapObservable(valueAccessor()),
            src      = ko.utils.unwrapObservable(value.src),
            fallback = ko.utils.unwrapObservable(value.fallback),
            $element = $(element);

        //now set the src attribute to either the bound or the fallback value
        if (src) {
            $element.attr("src", src);
        } else {
            $element.attr("src", fallback);
        }
    },
    init: function (element, valueAccessor) {
        var $element = $(element);

        //hook up error handling that will unwrap and set the fallback value
        $element.error(function () {
            var value = ko.utils.unwrapObservable(valueAccessor()),
                fallback = ko.utils.unwrapObservable(value.fallback);

            $element.attr("src", fallback);
        });
    },
};

That’s all there is to it – you can now specify a “primary” and a “fallback” binding for your images to get something like the effect below:

image

Another problem solved by the Swiss army knife that is knockout custom bindings.

Single Page Applications using Node & Knockout

This post is going to be a short walkthrough on how to use Node and KnockoutJS to create a simple single page application.

What is a Single Page Application?

…a web application or web site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application

That’s according to Wikipedia.  For the purposes of this post, a single page application (or SPA) will mean a web application for which we only want to serve up one HTML page.

That page will then link to a couple of javascript files which, in cohort with a templating engine, will create and manipulate the content of the page.  All communication with the server will be through AJAX, and will only ever transfer JSON data – no UI content.

We will be using node to serve the page (plus scripts, styles, etc.) and to handle the API calls, while knockout will provide us with the client-side interaction and templating.

Serving the Single Page

First up: we need to configure node to serve up our single HTML page:

<html>
	<body>
		<h1>I'm a single page application!</h1>
	</body>
</html>

We’ll be adding more to that later, but let’s get node working first.

Express

We’re going to be using expressjs to implement the more interesting API calls later on, but we can make use of it here to serve up a static file for us as well.  To install express, use the node package manager by running the command below.:

npm install express

Now we need to create a javascript file – app.js – to run in node.  This file will grab a reference to express using the require function and will start listening on port 3000.

var express = require("express"),
	app = express();

//start listening on port 3000
app.listen(3000);

Let’s see what happens when we run this.  In a command prompt, browse to the folder containing app.js and enter the command below to start node.

node app.js

Next, open your favourite browser and navigate to http://localhost:3000/index.html.  You should see something like this:

cannot-get

This is express telling us that it cannot resolve the URL “/index.html”, which isn’t unreasonable – we haven’t told it how to yet.  We want express to respond with the contents of static files from the current folder (eventually including our styles and javascript), so let’s get that set up.

We do this in the app.configure method (before we call app.listen) using the express.static method and the current application folder (stored in the special __dirname node variable).

app.configure(function() {
	//tell express to serve static files from the special
	//node variable __dirname which contains the current
	//folder
	app.use(express.static(__dirname));
});

Restart the node application, refresh the browser and you should now see the content from our single page:

can-get

Conveniently, express will automatically return index.html if you don’t specify a file name, so we can get the same response from http://localhost:3000/

Creating the Page

The next step is to start building up content in the page.  We are going to need a few javascript resources – jQuery for the AJAX calls, Knockout for the view model – and I’m going to include my command pattern implementation to help with the actions.

For the page itself I’m going to pull in a page.js to contain our page-specific code, and we should probably include a stylesheet as I can’t stand Times New Roman.

Our HTML page now looks like this:

<html>
	<head>
		<title>SPA Example</title>
		<link rel="stylesheet" href="spa.css" />
	</head>
	<body>
		<h1>I'm a single page application</h1>
	</body>
	<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.0.min.js"></script>
	<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
	<script src="https://raw.github.com/stevegreatrex/JsUtils/master/JsUtils/utils.min.js"></script>
	<script src="page.js"></script>
</html>

I’m using a CDN for jQuery and knockout, and I’m pulling my command implementation direct from Github (sorry Github!). I’m assuming that both spa.css and page.js are in the same folder as index.html

Refresh the browser again (no need to restart node this time) and…
styled
Much better!

Creating the View Model

As this is just a sample application I don’t want to get too distracted by the view model – the purpose of this post is demonstrate the end-to-end rather than to focus on a specific functionality.  With that in mind, let’s use the example functionality of a basic todo app (as that seems to be the thing to do).

Our view model will start off with a list of todo items which we will store in a knockout observableArray.  Each todo item will have a name and a complete flag.

For the time being, we’ll bootstrap the collection with a few sample items.

var TodoViewModel = function(data) {
	this.name = ko.observable(data.name);
	this.complete = ko.observable(data.complete);
};

var TodoListViewModel = function() {
	this.todoItems = ko.observableArray();
};

$(function() {
	var viewModel = new TodoListViewModel();

	//insert some fake todo items for now...
	viewModel.todoItems.push(new TodoViewModel({ name: "Pending Item", complete: false }));
	viewModel.todoItems.push(new TodoViewModel({ name: "Completed Item", complete: true }));

	ko.applyBindings(viewModel);
});

The view model is now being populated but there’s still nothing to see in our view – we need to add some HTML and start working with the knockout templating engine to get things to display.

Displaying Items using Knockout Templating

With knockout, the UI is data bound to the view model in order to generate HTML.  http://knockoutjs.com/ has a wealth of documentation and examples on how to achieve this, but for this example we are going to use three bindings: foreach to iterate through each of the todo list items; text to display the name; and checked to display the completed state.

<ul data-bind="foreach: todoItems">
	<li>
		<span data-bind="text: name"></span>
		<input type="checkbox" data-bind="checked: complete" />
	</li>
</ul>

Refresh the page in a browser and you should now see something like this:

items

We now have the text and the completed state of the our two fake todo items.  That’s all well and good, but what about when you want to get real data from the server?

Getting Real Data from the Server

In a single page application, data is acquired from the server using AJAX calls and our example today will be no different.  Unfortunately, our server doesn’t support any AJAX calls at the moment, so our next step is to configure a URL that will return some data; in this case: todo list items.

Configuring API Calls using Express

We want to set up an API call on our node server that will respond with a JSON list of todo items for the URL:

GET /api/todos

To set this up in express we use the app.get method, which accepts a path as the first parameter – in this case /api/todos – and a callback as the second.

app.get("/api/todos", function(req, res) {
	//...
});

The callback will now be invoked whenever we browse to http://localhost:3000/api/todos.  The two parameters on the callback are the request and the response objects, and we now want to use the latter to send JSON data back to the client.

Ordinarily you would be getting the data from some kind of backing store, but to keep things simple I’m just going to return a few fake items using the res.json method.  Here we are passing in the HTTP response code (200 – OK) and our data, then calling the res.end method to finish the response.

res.json(200, [
	{ name: "Item 1 from server", complete: false },
	{ name: "Item 2 from server", complete: false },
	{ name: "Completed Item from server", complete: true }
]);
res.end();

Now let’s hook up our view model to access that data…

Getting the View Model Speaking to the Server

As our server now expects a GET call we can use jQuery.getJSON to load the data from the client side.  Once we have the data, all we need to do is push it into our view model to update the UI.

var TodoListViewModel = function() {
	var self = this;
	this.todoItems = ko.observableArray();

	this.refresh = ko.command(function() {
		//make a call to the server...
		return $.getJSON("/api/todos");
	}).done(function(items) {
		//...and update the todoItems collection when the call returns
		var newItems = [];
		for (var i=0; i < items.length; i++ ){
			newItems.push(new TodoViewModel(items[i]));
		}
		self.todoItems(newItems);
	});

	//refresh immediately to load initial data
	this.refresh();
};

Note that I’ve used the command pattern in this example (to get some free loading indicators and error handling) but there’s no need to do so – a regular function would suffice.

Restart node, refresh the page and you should now see the data returned from the server.

server-items

Sending Data back to the Server

We’ve managed to display data from the server, but what about if we want to save a change from the client?

Let’s add another API method that expects a PUT call to /api/todos/[id] with a body containing the JSON data.  We’ll also need to add an id property to the fake data returned by the server so that we can reference it in the URL.

The configuration of the PUT URL looks very similar to the GET configuration from earlier.

app.put("/api/todos/:todoId", function(req, res) {
    //...
});

The only difference (besides the verb) is that our URL path now includes a parameter named “todoId”, signified by the prefixed colon.  This will allow us to access the value of the ID appended to the URL through the req.params object.

Our handler will also need access to the body of the request, and to provide that we need to configure express to use its body parser:

app.use(express.bodyParser());

Now we have access to the body of the request through the req.body property.

As our server doesn’t have a real backing store, there isn’t much we can do to actually process this call.  To demonstrate that it is actually getting through we’ll just log the details to the node console and respond with a 200 - OK for the time being.

app.put("/api/todos/:todoId", function(req, res) {
	console.log(req.params.todoId + ": " + JSON.stringify(req.body, null, 4));
	res.send(200);
	res.end();
});

We now need our view model to call this method whenever the value of the complete flag is updated by the user.  First off, lets add another command that uses jQuery to make an AJAX call with the appropriate data.

var TodoViewModel = function(data) {
	// as before

	this.updateServer = ko.command(function() {
		return $.ajax({
			url: "/api/todos/" + data.id,
			type: "PUT",
			contentType: "application/json",
			data: JSON.stringify({
				id: data.id,
				name: self.name(),
				complete: self.complete()
			})
		});
	});
};

This one is a bit more verbose than the getJSON call earlier as we need to call the jQuery.ajax method directly in order to PUT data.  It is also worth noting that the JSON object being sent is derived from the updated values for the name and complete fields from the relevant observables.

We can now use the subscribe method on the observable complete flag to ensure that this update function will be automatically invoked whenever the flag changes.

this.complete.subscribe(this.updateServer);

Restart node, refresh the page, and try clicking on the check boxes.  You should see confirmation of the successful call to the server in the node window.

server-output

Wrapping Up

This has only been a very simple example, but hopefully demonstrates the architecture of a single page application and how it can be implemented using node and knockout.

Publish & Subscribe Distributed Events in JavaScript

Having recently spent some time working in WPF withthe fantastic Composite Application Block (or Prism), I thought I would try bringing one of the more useful features over to JavaScript.

Distributed Events

Distributed events within Prism allow you to define a named event that can be published or subscribed to without the need to have a reference to any other object that depends on the event.

CompositePresentationEvent<string> anEvent; //injected somehow

//publish data anywhere in the application
anEvent.Publish("some event data");

//and consume it anywhere.  You just need a reference to the event
anEvent.Subscribe(data => MessageBox.Show(data));

When you are writing a large-scale application this is extremely useful, as it allows very loose coupling between components: if an object is interested in the current selected date then it just subscribes to the DateChanged event; it doesn’t care where the event is raised from.

Compare this to the traditional event subscription mechanism within .NET – where you need to know the parent object to subscribe – and it is easy to see that this method scales better as a system grows.

Brining Distributed Events to JavaScript

Given the different natures of web and application development I have not felt too strong a need to pull this functionality over into my JavaScript development, but as I work on larger and more modular single page web applications I am beginning to see a use for them.

So what are the requirements here? I want to be able to

  • subscribe to an event without knowing where the change came from
  • publish an event from multiple sources
  • subscribe to an event in multiple locations
  • acquire and refer to events by name*

*in Prism I would generally use a type to refer to an event, but we don’t have types so we’ll use names instead

//publish the current time to the "datechanged" event
$.publish("datechanged", new Date());

//and consume changes to the date anywhere in the application
$.subscribe("datechanged", function(date) {
    alert(date);
});

Ideally I would also like to add a couple of extra features:

  • Async Invocation – the publisher should (optionally) not have to wait for the subscribers to finish processing the event
  • Stateful Events – the subscriber should be able to subscribe after a publication and still receive the details

Implementation

Let’s start off with the subscription, as that will dictate how publication works.

Storing Subscriptions

The first thing is to be able to store multiple subscribers against a named event, and the simplest way to do that is to use an object with array properties:

//create an events object to store name -> event mappings
var events = {},

	//and use a function to create singleton event objects as needed
	getEvent = function(eventName) {
		if (!events[eventName]) {
			events[eventName] = {
				subscribers: []
			};
		}
		
		return events[eventName];
	};

Here we have a getEvent method that will check to see if the named event already exists, and will create an empty one if needed.

Note: I’m using an object with a subscribers array property (instead of just the array itself) so that we can store a bit of metadata alongside the subscriber list later.

The subscribe method then becomes:

$.subscribe = function (event, callback) {
	var subscription;

	if (typeof callback === "function") {
		subscription = { callback: callback };
	} else {
		subscription = callback
		if (!subscription.callback) {
			throw "Callback was not specified on options";
		}
	}
	
	getEvent(event).subscriptions.push(subscription);
};

This creates a subscription object containing the callback function (again, using an object to allow some metadata storage later), then uses the getEvent method from earlier to acquire or create the event object and append to the list of subscribers.

We’re allowing this to be called with either a callback function or an options object as the second parameter, so that users that don’t want to specify extra options can use a less verbose syntax.

Publishing Events

Now that we have a list of subscribers attached to each event it is simple enough to write the publish implementation: all we need to do is find the list of subscribers for the event and invoke the callback on each.

$.publish = window.Utils.publish = function (eventName, data) {
	var subscriptions = getEvent(eventName).subscriptions;
	
	for (var i = 0; i < subscriptions.length; i++) {
		(function (subscription, data) {
			subscription.callback.call(null, data);
		}(subscriptions[i], data));
	}
};

Supporting Async Events

Quite often, the object sourcing the event doesn’t need to wait on the objects that are listening to events. One of the benefits of loose coupling like this is that producers can ignore the actions of consumers, but at the moment our implementation will cause the publishing object to block until all of the subscribers have finished processing…which could take a while.

To work around this problem we can allow each subscriber to specify whether they want their event to be processed synchronously or asynchronously. With JavaScript being single-threaded (sorta) this means something slightly different to what it would in a WPF application, but the important part is to avoid blocking the publisher.

We can use setTimeout with a low value (or the minimum value) in our publish implementation to allow the publisher to continue processing uninterrupted, and then for our event handler to execute once it is completed.

if (subscription.async) {
	setTimeout(function () {
		subscription.callback.call(null, data);
	}, 4);
} else {
	subscription.callback.call(null, data);
}

Here we are determining whether or not to use async processing based on a flag on the subscription, and as we allowed an options object to be passed into our subscribe function we don’t need any changes there:

$.subscribe("event", {
  async: true,
  callback: function() { /*...*/ }
});

You can see the difference in behaviour between sync and async event handlers in this jsFiddle example.

Stateful Events

Perhaps “stateful” isn’t the best name for this concept, but it makes sense to me as the event is aware of it’s last publication, so it has a state.

The use case for this feature is where a subscriber relies on a piece of information being published, but it cannot guarantee that it will subscribe before that publication.

The implementation is simple enough: take a copy of the event payload on each publish…

getEvent(event).lastPayload = data;

…and then serve it up as if it were a new publication whenever a subscriber requests to be ‘stateful’ in the subscribe method…

if (subscription.stateful) {
	subscription.callback.call(null, getEvent(event).lastPayload);
}

As with the async implementation, we are already allowing users to specify an options object when they subscribe so there’s no need for any further changes.

//publish some important information
$.publish("eventname", "some data");

//...wait a while...

//then later, when something else subscribes
$.subscribe("eventname", function(data) {
    //this will be called immediately with "some data"
});

Source & Download

I’ve packaged this up alongside my various KnockoutJS utilities (available here) – which have also had a bit of cleaning up in the last week – but as this doesn’t rely on the Knockout library you can grab a separate copy here.

Server-Side Paged Lists in Knockout

After my last post on client-side paging using Knockout I had a few people comment that it would be useful if something reusable could handle server-side paging. It’s not quite what I needed but it sounded useful so I thought I’d see what I could come up with…

Strategising the Server

Server-side paging poses a slightly different problem to paging on the client-side as it requires (obviously) some cooperation from the server. Given that the server might be implemented in any of a hundred different ways I decided to use a strategy pattern to actually load the data:

var ViewModel = function() {
    this.pagedList = ko.pagedList({
        loadPage: function(pageIndex, pageSize) {
            //load data here
        }
    });
};

The requirements of the strategy are:

  1. Accept a pageIndex and pageSize to be loaded
  2. Return a jQuery.Deferred instance (such as that returned by $.ajax)
  3. Resolve the deferred object with a value that contains an array rows property

Assuming that the server response needs no modification (i.e. already has an array rows property) then a paged list can be created as below:

var ViewModel = function() {
    this.pagedList = ko.pagedList({
        loadPage: function(pageIndex, pageSize) {
            return $.getJson("/getPage?index=" + pageIndex + "&size=" + pageSize);
        }
    });
};

Getting the Total Number of Rows

When writing this I was keen to avoid enforcing anything on the server implementation that wasn’t absolutely necessary, and one of the things I decided wasn’t needed was the total number of available rows. As the client side component cannot always know how many total rows are available, I decided that by default I would simply set the totalRows property to -1 and the pagedList will function perfectly without ever knowing how many rows are actually available – with the following limitations:

  • pageCount and totalRows will always return -1
  • nextPage will never prevent the user from moving to the next page, even if that page will be empty

That being said, I also wanted to support those scenarios where the total number of rows is available, so totalRows can be set in one of two ways:

Manually Set totalRows

As with any Knockout observable property the totalRows value can be set externally, and the pagedList will use whatever value is set to calculate pageCount and prevent moving beyond the final page using nextPage.

var vm = new ViewModel();
vm.pagedList.totalRows(100); //specify 100 rows total

Include totalRows in Server Response

The minimum requirement of the data returned from the page loading strategy is that it requires an array rows property, but if it also includes an integer totalRows value then this will automatically set the observable value on the pagedList.

this.pagedList = ko.pagedList({
    loadPage: function(pageIndex, pageSize) {
        var defer = $.Deferred();

        //this is an example of the expected response object from the server
        defer.resolve({
            rows: [1, 2, 3],
            totalRows: 100 //specify the total number of rows in the response
        });

        return defer;
    }
});

In this way we can either specify the total number of rows on the client side, on the server side, or not at all – and still use the pagedList in the same way.

Pre-Loading the First page

When the page containing the pagedList is being generated on the server it is preferable that the first page of data already be loaded, rather than waiting on an unnecessary post back to the server to populate the list.

With that scenario in mind, I added the ability to specify the first page of data as another option on the constructor.

this.pagedList = ko.pagedList({
    loadPage: function(pageIndex, pageSize) {
        //...
    },
    firstPage: {
        rows: [1,2,3],
        totalRows: 100
    }
});

If this option is specified then the pagedList will not attempt to load the first page of data and will instead render the data specified in the option.

Note: this is also another mechanism by which the totalRows property can be pre-populated on the client side.

Mapping Data to ViewModels

In most cases the server will be returning something more complicated than the numeric values in the examples above, and in those cases it is common to want to wrap the returned object in a view model of it’s own.

To support this functionality I included a map constructor parameter that will be invoked on each of the rows returned from the page load strategy.

this.pagedList = ko.pagedList({
    //...
    map: function(item) {
        return ko.mapping.fromJS(item);
    }
});

Note: this example makes use of the Knockout mapping plugin to generate a view model.

Bindable Properties

Much of the behaviour is similar to the pagedObservableArray as it was described in my original post, with the most significant difference being that the returned object can be used directly – there is no need to bind to a page property as there was before. It also exposes the following properties:

  • pageSize – An observable instance containing the number of items per page
  • pageIndex – An observable instance containing the zero-based current page index
  • totalRows – An observable instance containing the total number of rows that are assumed to be available (or -1 if this has not been determined)
  • pageCount – A computed observable that returns the number of pages of data available (or -1 if totalRows is unknown)
  • previousPage – A command that moves to the previous page, if possible
  • nextPage – A command that moves to the next page, if possible
  • loadPage – A command that loads the page data at the index specified as the first parameter. The loadPage.isRunning observable should be used for all loading notifications

One point to note is that this implementation does not expose an observableArray containing the data; instead it exposes a regular observable with a value that is an array. This may seem a little strange but I felt that the additional functions and properties on the observable array do not really make sense when talking about a collection of server-specified data.

Source Code & Samples

The source code and unit tests are available on GitHub, and a working sample is available on jsFiddle.

If anyone else has any other suggestions or requests just let me know in the comments!