0

I have been searching Google to get some ideas and I found some code but it's incomplete and hard to understand. I want to use knockout to bind a list of images.

What's the best way to set up a spinner background while the images are loading. I have a spinner class I can set and unset to the background image.

Here is the code but it's not clear

 ko.bindingHandlers.Loading = {
        update: function (element, valueAccessor, allBindingsAccessor) {
            var value = valueAccessor(), allBindings = allBindingsAccessor();
            var valueUnwrapped = ko.utils.unwrapObservable(value);

            if (valueUnwrapped == true)
                $(element).showLoading(); // Make the element visible
            else
                $(element).hideLoading();   // Make the element invisible
        }
    };

and then use it like

<div data-bind="Loading: isLoading" >

update

    <img src="http://www.aero-sa.com/images/ajax-loader.gif" data-bind="visible:loading" />
var model = function() {
    var self = this;
    this.loading =  ko.observable(true);
    setTimeout(function() {
        self.loading(false);
    }, 4000);
}
ko.applyBindings(new model());

i have few question on the above code. what is this here? this point to what? when i write the code like then image is not getting hide....why this is not working.

var model = function() {
        //var self = this;
        this.loading =  ko.observable(true);
        setTimeout(function() {
            this.loading(false);
        }, 4000);
    }
    ko.applyBindings(new model());

please explain if possible.

Thomas
  • 33,544
  • 126
  • 357
  • 626
  • malsup.com/jquery/block/#demos – Thomas Jul 11 '13 at 09:53
  • Why don't you just have a "loading" boolean in your model and have an image in the html with `` – mael Jul 11 '13 at 10:35
  • can u plzz give me sample code....i can not visualize how to do it. thanks – Thomas Jul 11 '13 at 10:45
  • Something like that: http://jsfiddle.net/BZLYK/1/ – mael Jul 11 '13 at 10:54
  • i update my question....please have a look. thanks – Thomas Jul 11 '13 at 12:08
  • "This" refers to the current scope. In the model, it refers to the model scope. In setTimeout... well I'm not sure. Probably to the global scope. For that reason, you need to assign "this" (aka the model scope) to a variable (self) to be able to access it in setTimeout. But setTimeout was there for the example, I doubt you'll be using it. – mael Jul 11 '13 at 12:21

1 Answers1

0

I had a similar problem. In my case, I needed to hide a whole block of HTML if an image inside the block could not be loaded. I ended up using the imagesLoaded library (https://github.com/desandro/imagesloaded), which I wrapped in a knockout custom binding :

function tryRegisterEvent(imgLoad, event, handler) {
    if (handler === undefined) return;

    imgLoad.on(event, handler);
}

function tryRegisterEvents(imgLoad, events, bindings) {
    for (var i = 0; i < events.length; ++i) {
        var event = events[i];
        tryRegisterEvent(imgLoad, event, bindings[event]);
    }
}

ko.bindingHandlers['imagesLoaded'] = {
    'init': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        if (imagesLoaded === undefined) {
            throw new Error('imagesLoaded is not defined');
        }

        var bindings = ko.utils.unwrapObservable(valueAccessor());

        var imgLoad = imagesLoaded(element);

        tryRegisterEvents(imgLoad, ['always', 'done', 'fail', 'progress'], bindings);
    },
    'update': function () {}
};

Then I could use this binding in my HTML, as follow:

<div data-bind="visible: isLoading() || isLoaded()">
    Some more HTML and text...
    <img src="..." data-bind="imagesLoaded: { done: function () { isLoaded(true); }, always: function () { isLoading(false); } }" />
</div>

I initially set isLoading to true and isLoaded to false, and the event handlers would then change my view model's state accordingly, based on the image load status.

Note that since the imagesLoaded library can work with container instead of single images (and monitor all images inside the container), you can use this custom binding on a parent element containing all your image gallery, then display your spinner and hide it when the always event is triggered.