问题
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>
回答1:
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:
- you don't have to repeat
RootTarget
- the
with
automatically unwraps the observables so you can just writewith: RootTarget
, no parens needed - it works for the case when the
RootTarget
value isnull
orundified
so it hides the inputs while your original solutionRootTarget().ID
would throw a null reference exception.
回答2:
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;
来源:https://stackoverflow.com/questions/17612550/mapping-json-with-knockout-fails-to-populate-type-defined-object-properties