我正在尝试在嵌套的JSON对象上使用Knockout的映射插件,其中包含可变数据。但是,我不确定如何在HTML中显示它。如何正确映射所有嵌套的JSON对象并将其显示为简单的字符串?这是我的代码:
JS
var ListModel = function(jsonData) {
var self = this;
self.master = ko.mapping.fromJS(jsonData);
}
var listModel = new ListModel(jsonData);
ko.applyBindings(listModel);
HTML
<!-- ko foreach: master -->
<div data-bind="text: $data"></div>
<!-- /ko -->
示例JSON
{"Level 1a":"Hi","Level 1b":{
"Level 2a":"Hello","Level 2b":{
"Level 3":"Bye"}
}
}
示例输出
Hi
Hello
Bye
我在这里要做的主要是打印出所有嵌套级别的值。关键值和嵌套级别的数量是完全可变的(我在SO和在线上找到的大多数嵌套JSON示例都是固定密钥)。这可能吗?
更新:我找到了jQuery equivalent,但我仍然需要针对observable的Knockout实现。
答案 0 :(得分:5)
由于您的JSON对象具有可变键,因此您必须首先将其转换为固定的可预测结构,否则嵌套模板映射将无效(敲除是声明性的,因此您需要事先知道键名称。)
考虑以下自定义映射代码(不需要挖空映射插件):
var ListModel = function(jsonData) {
var self = this;
self.master = ko.observableArray([]);
function nestedMapping(data, level) {
var key, value, type;
for (key in data) {
if (data.hasOwnProperty(key)) {
if (data[key] instanceof Object) {
type = "array";
value = ko.observableArray([]);
nestedMapping(data[key], value());
} else {
type = "simple";
value = ko.observable(data[key]);
}
level.push({key: key, type: type, value: value});
}
}
}
nestedMapping(jsonData, self.master());
}
函数nestedMapping()
会改变您的数据结构:
{
"Level 1a": "Hi",
"Level 1b": {
"Level 2a": "Hello",
"Level 2b": {
"Level 3": "Bye"
}
}
}
成:
[
{
"key": "Level 1a",
"type": "simple",
"value": "Hi"
},
{
"key": "Level 1b",
"type": "array",
"value": [
{
"key": "Level 2a",
"type": "simple",
"value": "Hello"
},
{
"key": "Level 2b",
"type": "array",
"value": [
{
"key": "Level 3",
"type": "simple",
"value": "Bye"
}
]
}
]
}
]
现在你可以像这样创建一个模板:
<script type="text/html" id="nestedTemplate">
<!-- ko if: type == 'simple' -->
<div class="name" data-bind="text: value, attr: {title: key}"></div>
<!-- /ko -->
<!-- ko if: type == 'array' -->
<div class="container" data-bind="
template: {
name: 'nestedTemplate',
foreach: value
}
"></div>
<!-- /ko -->
</script>
看到它正常工作:http://jsfiddle.net/nwdhJ/2/
请注意关于nestedMapping()
的一个微妙但重要的观点。它创建了嵌套的observables / observableArrays。但它适用于 native 数组实例(通过将self.master()
和value()
传递到递归中)。
这样可以避免在对象构建过程中出现不必要的延迟。每次将值推送到observableArray时,它都会触发敲除更改跟踪,但我们不需要这样做。使用本机数组会快得多。
答案 1 :(得分:2)
将您的JSON数据更改为此(请注意数组!):
[
{
"Text": "Hi",
"Children": [
{
"Text": "Hello",
"Children": [
{
"Text": "Bye"
}
]
}
]
}
]
并使用自引用模板:
<script type="text/html" id="nestedTemplate">
<div class="name" data-bind="text: Text"></div>
<div class="container" data-bind="
template: {
name: 'nestedTemplate',
foreach: Children
}
"></div>
</script>
你这样称呼:
<div class="container" data-bind="
template: {
name: 'nestedTemplate',
foreach: master
}
"></div>
然后您可以使用CSS来管理缩进:
/* indent from second level only */
div.container div.container {
margin-left: 10px;
}
在jsFiddle上查看:http://jsfiddle.net/nwdhJ/1/