I’m having some trouble understanding how ko.mapping.fromJS and ko.mapping.toJS work.
Here the explanation of my problem simplified:
I have a Risk Array object coming from the Server, that Risk array has a Places array.
For some strange reason, after calling the ko.mapping.FromJS my child Places array gets cleared or hidden, so my template can’t access its contents… I found that by using ko.mapping.ToJS I can get access to Places contents but by doing this It doesn’t seem to refresh my template after adding an Item!
I’m trying to build a very simple grid where I can add places to the first Risk in the array for simplification purposes:
var FromServer = {"Risk":[{"SourceKey":0,"Places":{"Place":[{"SourceKey":1}]}}]}
var viewModel =
{
places : ko.mapping.fromJS(FromServer.Risk[0].Places.Place),
addPlace : function()
{
alert('Entering add place, places count:' + this.places.length);
this.places.push({SourceKey:"New SK"});
}
}
//If I leave this line it will update list but not refresh template
//If I comment it out it will show my Places array as empty!!!
viewModel = ko.mapping.toJS(viewModel)
ko.applyBindings(viewModel);
Here my sample HTML code for my grid:
<p>You have asked for <span data-bind="text: places.length"> </span> place(s)</p>
<table data-bind="visible: places.length > 0">
<thead>
<tr>
<th>SourceKey</th>
</tr>
</thead>
<tbody data-bind='template: { name: "placeRowTemplate", foreach: places}'></tbody>
</table>
<button data-bind="click: addPlace">Add Place</button>
<script type="text/html" id="placeRowTemplate">
<tr>
<td><input class="required" data-bind="value: $data.SourceKey, uniqueName: true"/></td>
</tr>
</script>
Here is my jsFiddle: jsFiddle Sample
My question is: why do I have to unwrap my viewModel with ko.mapping.ToJS so I can manipulate my child array?, and how can I have my template refreshing in this scenario?
Please help!
You had a few things wrong with your code. New JSFiddle here:
http://jsfiddle.net/ueGAA/4/
You needed to create an observable array for the places array, otherwise knockout will not know when it has been updated. The method call is
ko.observableArray(arrayVar)
You do no want to call toJS on your view model. That unwraps all of the observables and makes Knockout not capable of updating your bindings
When referencing an observable array, you need to use parens: ie. viewModel.places().length.
In your FromServer object your Place object contained an array with the object {“SourceKey”: 1} inside of it. I assumed you intended for the place object to just have a simple property called SourceKey