Well, I did it with an extender the following way:
ko.extenders.preloadImage = function(target, lazyImage) {
var preloadedImage = null;
var lazyLoadImage = lazyImage || "img/ajax-loader.gif";
//create a writeable computed observable to intercept writes to our observable
var result = ko.computed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target();
if(newValue == lazyLoadImage || newValue == preloadedImage) {
valueToWrite = newValue;
} else {
preloadedImage = newValue;
valueToWrite = lazyLoadImage;
$('<img />').attr('src', newValue).load(function() {
valueToWrite = newValue;
preloadedImage = null;
target(valueToWrite);
target.notifySubscribers(valueToWrite);
});
}
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written,
// force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
});
//initialize with current value
result(target());
//return the new computed observable
return result;
};
And you can use it the following way:
var BookModel = function(data) {
var self = this;
self.id = ko.observable(data.id);
self.title = ko.observable(data.title);
self.pages = ko.observable(data.pages);
self.pictureURL = ko.observable(data.pictureURL).extend({ preloadImage : null });
};
It works with a default img/ajax-loader.gif
picture or another picture you pass as the lazyImage
parameter. Basically, whenever a new picture is to be displayed, the lazy loading gif is displayed instead. Only when the original picture has been preloaded by the browser does it really show on screen.
This is not much, but it may be helpful to KnockoutJS lovers out here :-) Also, if you think it could be better, please edit the code.