I'm trying to create a custom binding that will show a loading gif while content is loading.
ko.bindingHandlers.loader = {
init: function (element) {
$('<div>').addClass('loader').hide().appendTo($(element));
},
update: function (element, valueAccessor) {
var isLoading = ko.utils.unwrapObservable(valueAccessor());
var $element = $(element);
var $children = $element.children(':not(.loader)');
var $loader = $(element).find('.loader');
if(isLoading) {
$children.stop(true).css('visibility', 'hidden').attr('disabled', 'disabled');
$loader.stop().fadeIn();
} else {
$loader.stop(true).fadeOut(function () {
$children.css('visibility', 'visible').removeAttr('disabled');
});
}
}
};
I can see in the init that div.loader
is being appended to the element
, and can see the update function fire when isLoading
is changed to true. But once the images have loaded (by loaded i mean each image returns a resolved promise on the their respective load event) I don't see the update firing once isLoading
is set back to false.
viewModel
function viewModel() {
var self = this;
self.movies = ko.observableArray([]);
self.searchValue = ko.observable();
self.isLoading = ko.observable(false);
self.search = function () {
self.isLoading = true;
$.getJSON(arguments[0].action, { name: this.searchValue() }, function (data) {
self.movies(data);
$.when.apply($, promises).done(function() {
setThumbnailHeight(function () {
self.isLoading = false;
});
});
});
};
var setThumbnailHeight = function(callback) {
var $items = $('.thumbnails li');
var maxHeight = Math.max.apply(null, $items.map(function () {
return $(this).innerHeight();
}).get());
$items.css('height', maxHeight);
callback();
};
}
ko.applyBindings(new viewModel());
setThumbnailHeight
is being called at the correct time (once all promises have resolved) and is working properly, in that I see it setting the height of each li
to the max height and can see the callback (in this case function(){ self.isLoading = false; }
being called.
my binding
<ul class="content thumbnails" data-bind="foreach: movies, loader: $root.isLoading">
<li class="movie">
...
</li>
</ul>
So just to recap, the problem is that the loading gif will be displayed when isLoading
is set to true but is not hiding and showing the newly loaded content when it's set back to false.
All observables are function so you cannot assign value to it using =
. Use self.isLoading(true);
instead of self.isLoading = true;
self.search = function () {
self.isLoading(true);
$.getJSON(arguments[0].action, { name: this.searchValue() }, function (data) {
self.movies(data);
$.when.apply($, promises).done(function() {
setThumbnailHeight(function () {
self.isLoading(false);
});
});
});
};
function(){ self.isLoading(false); }