Reputation: 353
I'm trying to map JSON data using the knockout.mapping plugin, however the heirarcical JSON data fails to populate my object properties correctly, the top level loads fine but not the child 'RootTarget' data?
What am I doing wrong?
Knockout Javascript
var Query = function(json)
{
this.ID = ko.observable(0);
this.Name = ko.observable();
this.RootTargetID = ko.observable();
this.RootTarget = ko.observable();
var mapping = {
'RootTarget': {
create: function (args) {
return new QueryTarget(args.data, null);
}
}
};
ko.mapping.fromJS(json, mapping, this);
}
var QueryTarget = function(json, parent)
{
this.ID = ko.observable(0);
this.Name = ko.observable();
this.ParentID = ko.observable(0);
this.Parent = ko.observable(parent);
this.FilterID = ko.observable(0);
var mapping = {
'ignore': ["Parent"]
};
ko.mapping.fromJS(json, mapping, this);
}
var QueryModuleViewModel = function()
{
var json = {
"ID": 2,
"Name": "Northwind 2",
"RootTargetID": 2,
"RootTarget": {
"ID": 2,
"Name": "Customers",
"ParentID": null,
"FilterID": 2,
"Parent": null
}
};
this.QueryObj = new Query(json);
}
window.onload = function () {
ko.applyBindings(new QueryModuleViewModel());
};
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>TypeScript Knockout Mapping Query Test</title>
<link rel="stylesheet" href="app.css" type="text/css" />
<script src="Scripts/jquery-2.0.2.js" type="text/javascript"></script>
<script src="Scripts/knockout-2.2.1.debug.js" type="text/javascript"></script>
<script src="Scripts/knockout.mapping-latest.debug.js" type="text/javascript"></script>
<script src="my_js_query_test.js"></script>
</head>
<body>
<h1>TypeScript Knockout Mapping Query Test</h1>
<div data-bind="with: QueryObj">
<span data-bind="blah: console.log($context)"></span>
<p>Query Name: <input data-bind="value: Name" /></p>
<hr />
<p>Quick test of RootTarget Values</p>
<p>RootTarget.ID: <input data-bind="value: RootTarget.ID" /></p>
<p>RootTarget.Name: <input data-bind="value: RootTarget.Name" /></p>
</div>
</body>
</html>
Upvotes: 1
Views: 1304
Reputation: 139758
Because your RootTarget
is declared as an ko.observable
which is a function so you need to call it with empty args ()
to get its value and access the stored object.
So you just need to change your bindings and add the missing ()
:
<p>RootTarget.ID: <input data-bind="value: RootTarget().ID" /></p>
<p>RootTarget.Name: <input data-bind="value: RootTarget().Name" /></p>
Demo JSFiddle.
Or you can use here the with
binding
<p>Quick test of RootTarget Values</p>
<!-- ko with: RootTarget -->
<p>RootTarget.ID: <input data-bind="value: ID" /></p>
<p>RootTarget.Name: <input data-bind="value: Name" /></p>
<!-- /ko -->
Demo JSFiddle.
It has some nice advantages:
RootTarget
with
automatically unwraps the observables so you can just write with: RootTarget
, no parens neededRootTarget
value is null
or undified
so it hides the inputs while your original solution RootTarget().ID
would throw a null reference exception.Upvotes: 2
Reputation: 6793
You need brackets on your roottarget mappings as you need to evaluate the observable before you can get it's properties.
<p>RootTarget.ID: <input data-bind="value: RootTarget().ID" /></p>
Alternatively, RootTarget doesn't actually need to be an observable, only its properties do, so if you remove the line below it'll automatically be created as a normal object and your bindings will work as they are.
this.RootTarget = ko.observable;
Upvotes: 0