The Unculled Badger
The Unculled Badger

Reputation: 760

knockout.js async binding update

I have this code in my javascript view model using Knockout. Everything works as designed, apart from I am struggling to get the two way binding update to work when the callback from my async call returns. See the code below.

var ViewModel = function (counterparty, scenario) {
this.counterparty = ko.observable(counterparty);
this.scenario = ko.observable(scenario);
this.choice = ko.computed(function () {
    // Knockout tracks dependencies automatically. 
    //It knows that fullName depends on firstName and lastName, 
    //because these get called when evaluating fullName.        
    return this.counterparty() + " " + this.scenario();
}, this);

this.loginResult = ko.observable("");
// Do an asynchronous request to a rest service
var xmlhttp = new XMLHttpRequest();
var url = 'http://someloginurl';
xmlhttp.open('GET', url, true, 'user', 'pass');
xmlhttp.send(null);

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var response = xmlhttp.responseXML;
        this.loginResult = "Logged In To RNS Successfully";
    } else {
        // wait for the call to complete
    }
};
this.availableCountries = ko.observableArray([
    new Country("UK", 20000),
    new Country("France", 30000)]);
this.selectedCountry = ko.observable();


};
var Country =
function(name, population) {
    this.countryName = name;
    this.countryPopulation = population;
};

ko.applyBindings(new ViewModel("", ""));

So I require this bit of code to update the binding showing the new value in the html for this.loginResult... But this is not happening and I am not sure why..

I thought that this line this.loginResult = ko.observable(""); should ensure that the value was a 'two-way binding' but it seems not.. Anyone know why this does not update?

The html tag for this is as follows:

<p><span data-bind="value: loginResult"> </span></p>

if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var response = xmlhttp.responseXML;
        this.loginResult = "Logged In To RNS Successfully";
    } else {
        // wait for the call to complete
    }

Ok - I fixed this problem.. The solution is to refactor the code a little..

Firstly declare the variable upfront as an observable

// Do an asynchronous request to a rest service
this.loginResult = ko.observable('');
var url = 'someurl';

then refactor the method and pass in the variable so that its defined.
runAsyncRequest(url, this.loginResult);

function runAsyncRequest(url, loginResult) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url, true, 'user', 'pass');
xmlhttp.send(null);
xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var response = xmlhttp.responseXML;
        loginResult('Logged In To RNS Successfully');
    } else {
        // wait for the call to complete
    }
};

}

All then works swimmingly and the binding is updated.

Upvotes: 0

Views: 1167

Answers (1)

sphair
sphair

Reputation: 1670

To set a value in an observable, use

this.loginResult("Logged In To RNS Successfully");

Without the parenthesis, you are assigning a string variable to the loginResult, not filling it with data.

From the documentation on observables: (http://knockoutjs.com/documentation/observables.html)

To write a new value to the observable, call the observable and pass the new value as a parameter. For example, calling myViewModel.personName('Mary') will change the name value to 'Mary'.

Upvotes: 1

Related Questions