oshkosh
oshkosh

Reputation: 551

Knockout observables not being updated from within an event handler

I have a very simple code. I am using the textext jQuery plugin.

    $('#'+field).textext({ plugins: 'tags' }).bind('isTagAllowed', function(e, data){
    window.kmodel.enableButtons(false);
    window.kmodel.showError(false); 
    //make AJAX calls while stuff is disabled
    //re-enable

}

The problem is that the UI doesn't get updated until after the handler has exited, at which point it's already too late.

I guess I could use jQuery itself, but I find knockout much more elegant, and I really want to get to the bottom of this. Maybe knockout has a function like pushChanges or something?

http://jsfiddle.net/Ku2cj/1/

So here's the thing. If you leave the alert, the UI updates as expected. But if it's removed, the UI doesn't update.

Upvotes: 0

Views: 239

Answers (2)

sroes
sroes

Reputation: 15053

Probably because the browser is still executing the code, and since you set async to false, it's executing all the code synchronous and therefor doesn't have time to update the UI.

What if you change the following:

window.komodel.enableButtons(false);
window.komodel.showError(false);
window.komodel.showAdding(true);

  $.ajax({
      url: "/Ku2cj",
      async: false,
      timeout: 2000
  });

window.komodel.enableButtons(true);
window.komodel.showAdding(false);
window.komodel.showError(true);

With an asynchronous construction:

window.komodel.enableButtons(false);
window.komodel.showError(false);
window.komodel.showAdding(true);

$.ajax({
    url: "/Ku2cj",
    timeout: 2000
}).then(function() {
    window.komodel.enableButtons(true);
    window.komodel.showAdding(false);
    window.komodel.showError(true);
});

http://jsfiddle.net/kVLaK/

Upvotes: 1

rwisch45
rwisch45

Reputation: 3702

I believe that I have a version of this working for you that is using promises. I don't know anything about the texttext jQuery plugin, or how it might be interacting with KO in terms of DOM manipulation. That being said, what I have works but it may not be the solution you want.

Like you said, if you take out the alert from your original fiddle then the DOM is not correctly updated. You don't see the "adding" text - only the "error" text after the code inside the binding handler finished executing. But if you introduce promises into the equation, then you ensure that everything is happening in it's proper order. I used Q.js here because that's what I'm used to, but there are other libraries to use (or just use jQuery's $deffered)

Here is the updated fiddle. I added a method to your KO model called enable which sets the true/false values on the observables in your model. Here is the updated textext section

$('#textarea').textext({
    plugins: 'tags'
}).bind('isTagAllowed', function (e, data) {
    window.komodel.enable(false) // happens first
   .then(function () {
        $.ajax({  // only after first happens, ajax starts
            url: "/Ku2cj",
            async: false,
            timeout: 2000
        }).success(function () {
            window.komodel.enable(true); // after ajax is complete, this happens
        });

    });

});

Upvotes: 1

Related Questions