Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I show a "loader" during knockout.js initialization?

I have a single-page web-app built with knockout.js and jQuery Mobile.

The view-model initialization (i.e. the ko.applyBindings() function) takes about 7-8 seconds. During this time, the page shows blank.

$(document).ready(function () {
    ko.applyBindings(viewModel);
})

Is there a way to show the JQM loader in the meantime, or to show a kind of "splash screen", to give to the user a feedback that the "page is loading"?

Note that it seems to me that the solution proposed by @Jeroen is also good together with the default page transitions of jQuery Mobile, at least as I can see in this jsfiddle.

To be honest, the tip proposed by @Omar seems to me to have better integration with JQM, and I will try in the future to combine both answers, with a writeable computed observable to switch the JQM loader on/off.

like image 416
user2308978 Avatar asked Aug 29 '13 13:08

user2308978


1 Answers

Keep it simple! Show a loading overlay in your html by default, but use a visible: false binding of some kind. That way when the applyBindings call is done the UI will hide the overlay.

For example, suppose this view:

<div id="main">
    <div id="loading-overlay" data-bind="visible: loading"></div>
    Some content<br />
    Some content
</div>

And suppose this view model:

vm = { loading: ko.observable(true) };

Then calling this:

ko.applyBindings(vm);

If for whatever reason it takes 7 secs to load, the loading-overlay will be shown until the UI is updated.

This approach is great if you have a client side DAL or some single point where you run Ajax calls, because you can follow this pattern:

  1. vm.loading(true)
  2. Ajax call with callbacks for success and failure
  3. On callback do vm.loading(false)

Knockout will handle the overlay visibility for you.

See this fiddle for a demo, or check out this Stack Snippet:

vm = { loading: ko.observable(true) };

ko.applyBindings(vm);

// Mock long loading time:
window.setTimeout(function() {
    vm.loading(false);
}, 5000);
html { height: 100%; }

body {
    position: relative;
    height: 100%;
    width: 100%;
}

#loading-overlay {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    background: url('http://img.cdn.tl/loading51.gif') white no-repeat center;
    opacity: 0.75;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div id="main">
    <div id="loading-overlay" data-bind="visible: loading"></div>
    Some content<br />
    Some content<br />
    Some content<br />
    Some content<br />
    Some content<br />
    <input type='text' value='cant edit me until overlay is gone' /><br />
    <button>can't press me until overlay's gone!</button><br />
    Some content<br />
    Some content<br />
    Some content
</div>
like image 64
Jeroen Avatar answered Nov 15 '22 09:11

Jeroen