Etienne Noël
Etienne Noël

Reputation: 6166

KnockoutJS - binding does not update using mapping plugin

I have a view Model in Knockout that is mapped using the mapping plugin. I need to do so since the data (a JSON object) will be retrieved from a server using Ajax calls.

My problem is that when I modify a form, the mapped data isn't updated in the object...

You can also see this in action the following JSFiddle: http://jsfiddle.net/etiennenoel/4EXSy/6/

Here's my object retrieved from the server:

var dataContent = 
[
    {
        playerId: 2,
        playerName: "allo",
        evaluatedExercises: 
        [
            {
                id: 1,
                evaluationExerciseId: 1,
                numberOfTries: 6,
                tries: [
                    {
                    id: 0,
                    number: 0,
                    result: 0
                    }
                ]
            }       
        ]
    }
]

Here is the complete javascript view model:

function Try(id, number, result) {
    var self = this;

    self.id = id;
    self.number = number;
    self.result = result;
}

function ExerciseResult(id, evaluationExerciseId) {
    var self = this;

    self.id = id;
    self.evaluationExerciseId = evaluationExerciseId;
    self.tries = [];
}

function PlayerEvaluation(playerId, playerName) {
    var self = this;

    self.playerId = playerId;
    self.playerName = playerName
    self.evaluatedExercises = [];
}

function appViewModel() {
    var self = this;

    self.playersEvaluation = ko.observableArray();

    self.exportToJSON = ko.computed(function() {
        return ko.toJSON(self.playersEvaluation);
    }, this);

}

var viewModel = new appViewModel();

var dataContent = 
[
    {
        playerId: 2,
        playerName: "allo",
        evaluatedExercises: 
        [
            {
                id: 1,
                evaluationExerciseId: 1,
                numberOfTries: 6,
                tries: [
                    {
                    id: 0,
                    number: 0,
                    result: 0
                    }
                ]
            }       
        ]
    }
]

for(i = 0; i < dataContent.length; i++) {
    playerEvaluation = new PlayerEvaluation(dataContent[i].playerId, dataContent[i].playerName);

    evaluatedExercises = dataContent[i].evaluatedExercises;

    for(j = 0; j < evaluatedExercises.length; j++) {    
        exerciseResult = new ExerciseResult(evaluatedExercises[j].id, evaluatedExercises[j].evaluationExerciseId);
        tries = evaluatedExercises[j].tries;

        for(k = 0; k < tries.length; k++) {
            exerciseTry = new Try(tries[k].id, tries[k].number, tries[k].result)

            exerciseResult.tries.push(exerciseTry);
        }

        playerEvaluation.evaluatedExercises.push(exerciseResult);        
    }

   viewModel.playersEvaluation.push(playerEvaluation);
}

ko.mapping.fromJS(viewModel.playersEvaluation);
ko.applyBindings(viewModel)

This object is mapped in html using KnockoutJS:

    <table class="table table-hover table-bordered">
     <thead> <!-- This will be generated with Twig so it is normal that is does not correspond to the data below -->
         <tr>
             <th>Nom</th>
             <th colspan="6" style="text-align:center">Élément #1</th>

         </tr>
         <tr>
             <th></th>

             <th class="try">
                 1                 
             </th>
             <th class="try">
                 2                 
             </th>
             <th class="try">
                 3                 
             </th>
             <th class="try">
                 4                 
             </th>
             <th class="try">
                 5                 
             </th>
             <th class="try">
                 6                 
             </th>  

         </tr>
    </thead>
    <tbody data-bind="foreach: playersEvaluation">
        <tr data-bind="">
            <td data-bind="text: $data.playerName">
            </td>
           <!-- ko foreach: $data.evaluatedExercises -->
            <!-- ko foreach: $data.tries -->
            <td>
                <input type="text" data-bind="value: $data.result" />
            </td>
            <!-- /ko -->
            <!-- /ko -->
        </tr>
    </tbody>
</table>


<div data-bind="text: exportToJSON()">

</div>

When I modify the input, I want the changes to be reflected in the self.playersEvaluation variable of my viewModel. To do so, I created a computed Function that shows the content of the playersEvaluation in a div below the table.

However, the div does not get updated and therefore I came to the conclusion that the mapping must not be proper.

Where my mapping has gone wrong ?

Upvotes: 1

Views: 242

Answers (1)

Kevin Nacios
Kevin Nacios

Reputation: 2853

im not incredibly experienced with the mapping plugin, but i believe you should just let it build your view model structure for you (since you dont appear to have any more complex logic at any level of your view models)

http://knockoutjs.com/documentation/plugins-mapping.html

function appViewModel() {
    var self = this;
    self.playersEvaluation;   
}

var viewModel = new appViewModel();

// this creates observables for everything in dataContent. the result itself is an observable
// which you can set in your top level view model
viewModel.playersEvaluation = ko.mapping.fromJS(dataContent)
ko.applyBindings(viewModel);

Fiddle: http://jsfiddle.net/4EXSy/8/

Upvotes: 2

Related Questions