1
votes

I am trying to use a single page application example (knockout tutorial) and the mapping plugin to create a list of items that a user can click on (select). I need a default item to be selected from the beginning and this is where with the mapping plugin it does not work although it works with the bare knockout. Am I missing something? or How do you tame the mapping plugin?

HTML Part:

<ul data-bind="foreach: gamePlayers">
    <li class="clickable" data-bind="
              text: playerName, 
              css: { selected: playerId == $root.chosenPlayerId() },                              
              click: $root.selectPlayer">
    </li>
</ul>

JS common part :

var dataJS = {
    gamePlayers: [{playerId:1, playerName:"Sun"},{playerId:2,playerName:"Moon"}],
    playerActive:1
};

JS that does work :

function GameViewModel(data) {
    // Data
    var self = this;
    self.gamePlayers = ko.observableArray(data.gamePlayers);
    self.chosenPlayerId = ko.observable();

    // Behaviours    
    self.selectPlayer = function (player) { self.chosenPlayerId(player.playerId); };
    self.selectPlayer(data.gamePlayers[0]);
}

ko.applyBindings(new GameViewModel(dataJS));

JS that does not work :

my.vmPlayers = {};

function MyViewModel (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
    self.chosenPlayerId = ko.observable();
    self.selectPlayer = function (player) { self.chosenPlayerId(player.playerId); };
    self.selectPlayer(data.gamePlayers[0]);
}

var mapping = {
    create: function (options) {
        return new MyViewModel(options.data);
    }
};

my.vmPlayers = ko.mapping.fromJS(dataJS, mapping);
ko.applyBindings(my.vmPlayers);

Example of how it does not work http://jsfiddle.net/HeroEja/43AtS/

So this binding css: { selected: playerId == $root.chosenPlayerId() } is not evaluated on initial page load. Any idea why in much appreciated!

1

1 Answers

1
votes

The main problem is caused by this line:

self.chosenPlayerId(data.playerActive);

because in this context data won't be a JS object but data is holding the JSON string itself so data.playerActive will return undefined and your initial selection won't work.

What you need is:

self.chosenPlayerId(self.playerActive());  

because you anyway mapped your data into the self with ko.mapping.fromJS(data, {}, self);

And because of the mapping plugin playerId will be observable so you need to change your usages accordingly to make it work

So in your css binding:

css: { selected: playerId() == $root.chosenPlayerId() }

And in your selectPlayer method:

self.selectPlayer = function (player) {
    self.chosenPlayerId(player.playerId());
};

A fixed demo JSFiddle.