Swamy
Swamy

Reputation: 463

Refresh Knockout binding when the view model is updated with JSON data received from server

I have a knockout viewmodel which is updated with JSON data received from the server for each button click and would like to refresh the binding based on the changes to viewModel. I am using knockout mapping to convert the JSON to KO observables.

My question is the bindings are not refreshed when the viewmodel is updated on button click

The sample fiddle is here

JS:

    function getPlayersAsJSON(country) {
    var players = null;
    if (country === 'spain') {
        players = $('#spainText').val();
    } else if (country === 'swiss') {
        players = $('#swissText').val();
    }
    return players;
}

var viewModel = {
    players: ko.observableArray()
};

$(function () {
    $('#btnSearch').click(function () {
        var playerDataJSON = getPlayersAsJSON($('#drpCountry').val());
        var playerData = ko.mapping.fromJSON(playerDataJSON);
        console.log(playerDataJSON);
        console.log(playerData);
        console.log(playerData());
        viewModel.players(playerDataJSON);
    });
});

ko.applyBindings(viewModel);

HTML:

    <div>JSON Data for Spain
    <br/>
    <textArea id="spainText" rows="4" cols="50">[{"Name": "Nadal","Age": 28},{"Name": "Ferrer","Age": 32},{"Name": "Ferrer", "Age": 29}]</textArea>
    <br/>JSON Data for Swiss
    <br/>
    <textArea id="swissText" rows="4" cols="50">[{"Name": "Federer","Age": 32},{"Name": "Wawiranka", "Age": 28}]</textArea>
</div>
<br/>
<div>Select Country
    <br/>
    <select id="drpCountry">
        <option value="spain">spain</option>
        <option value="swiss">swiss</option>
    </select>
</div>
<input type="button" id="btnSearch" value="Search" />
<br/>
<table>
    <thead>
        <tr>
            <th>Name</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: players">
        <tr>
            <td data-bind="text: $data.Name"></td>
            <td data-bind="text: $data.Age"></td>
        </tr>
    </tbody>
</table>

Please let me know if you need more details

Upvotes: 2

Views: 9120

Answers (1)

nemesv
nemesv

Reputation: 139758

If the input is an array then ko.mapping.fromJSON will return a ko.observableArray.

So you need to write playerData() to unwrap the observable array otherwise you will end up your players observable array holding another observable array:

var playerData = ko.mapping.fromJSON(playerDataJSON);
viewModel.players(playerData()); //unwrap the playerData 

Demo JSFiddle.

As an alternative solution the mapping plugin supports to directly fill in an already existing observable arrays if the input is a JSON array, with the following syntax:

ko.mapping.fromJSON(playerDataJSON, {} /* empty options */, viewModel.players);

Demo JSFiddle.

Upvotes: 2

Related Questions