Reputation: 2282
I have a section of my page bound to a Knockout Viewmodel. When I click a link it loads some data and displays it a little farther down. I want to display a little loading img while it goes out and loads the data then hide it when it is complete. I have the following code (stripped down to show important parts). The Ajax call is NOT async, it was set to false for other code someone else is using so I cannot change it. The problem is the "self.Loading(false)" doesn't get fired until the ajax call is complete, so it doesnt appear to show up at all. If I switch the ajax call to async it works as intended. So I am wondering why the Ajax call is blocking the observables change since it is called before it, shouldn't it fire immediately. Is there a way to force it to trigger immediately.
HTML:
<a data-bind="click: GetInfo" href="javascript:;">
<img data-bind="visible: Loading" src="myimg.jpg" alt="Loading" />
</a>
KO:
self.Loading = ko.observable(false);
self.GetInfo = function () {
self.Loading(true);
AjaxCall().done(function (data){
self.Loading(false);
}
};
Upvotes: 0
Views: 74
Reputation: 65126
The observable and the DOM are likely being updated immediately, but you can't see it because the browser probably doesn't get around to drawing the screen. The request is blocking the redraw because... it's non-async. This is the exact reason you should not make non-async requests.
As a workaround you could try to force the event loop to spin once by using setTimeout
with a 0 timeout to run your horrible sync request after the observable change, but in all seriousness, just fix your request to be async. Browsers are not guaranteed to do anything (including running any loading animations) when your code is blocking.
Upvotes: 3
Reputation: 62
Try this
<a data-bind="click: GetInfo,valueUpdate: 'keyup'" href="javascript:;">
<img data-bind="visible: Loading" src="myimg.jpg" alt="Loading" />
</a>
Upvotes: 0