使用敲除映射显示嵌套的JSON数据

使用敲除映射显示嵌套的JSON数据,json,knockout.js,knockout-mapping-plugin,knockout-2.0,Json,Knockout.js,Knockout Mapping Plugin,Knockout 2.0,我试图在一个嵌套的JSON对象上使用Knockout的映射插件,该对象中包含变量数据。但是,我不知道如何让它显示在我的HTML中。如何正确映射所有嵌套的JSON对象,并将其显示为一个简单的字符串?这是我的密码: JS HTML 样本输出 Hi Hello Bye 这里我要做的主要事情是打印出所有嵌套级别的值。键值和嵌套级别的数量是完全可变的(我在SO和在线上找到的大多数嵌套JSON示例都是针对固定键的)。这可能吗 更新:我找到了,但我仍然需要用于可观察对象的敲除实现。将您的JSON

我试图在一个嵌套的JSON对象上使用Knockout的映射插件,该对象中包含变量数据。但是,我不知道如何让它显示在我的HTML中。如何正确映射所有嵌套的JSON对象,并将其显示为一个简单的字符串?这是我的密码:

JS

HTML

样本输出

Hi
  Hello
    Bye
这里我要做的主要事情是打印出所有嵌套级别的值。键值和嵌套级别的数量是完全可变的(我在SO和在线上找到的大多数嵌套JSON示例都是针对固定键的)。这可能吗


更新:我找到了,但我仍然需要用于可观察对象的敲除实现。

将您的JSON数据更改为此(注意数组!):

并使用自参考模板:


你这样称呼他:


然后可以使用CSS管理缩进:

/* indent from second level only */
div.container div.container {
  margin-left: 10px;
}

在JSFIDLE上查看它:

因为JSON对象有可变键,所以必须首先将其转换为固定的、可预测的结构,否则嵌套模板映射将不起作用(knockout是声明性的,所以需要事先知道键名)

考虑以下自定义映射代码(不需要敲除映射插件):

函数
nestedMapping()
将改变数据结构:

{
    "Level 1a": "Hi",
    "Level 1b": {
        "Level 2a": "Hello",
        "Level 2b": {
            "Level 3": "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>

看到它工作了吗

请注意关于
nestedMapping()
的一个微妙但重要的要点。它创建嵌套的可观测/可观测阵列。但是它可以处理本机数组实例(通过将
self.master()
value()
传递到递归中)


这样可以避免对象构造过程中不必要的延迟。每次您将值推送到observableArray时,它都会触发淘汰更改跟踪,但我们不需要这样做。使用本机数组会快得多。

您的JSON数据有固定的键(文本和子项),但我也需要考虑变量键。@Wei:从您的问题中不清楚这些变量键是什么样子的(我可以猜,但我不想)。如果您的密钥名称正在更改,knockout如何知道如何应用模板?此外,如果数据对象中的密钥名称发生变化,我认为它是代码嗅觉。如果键名是可变的,那么它们是数据而不是键。这是有道理的。好的,它们是可变的,因为传入的JSON数据可能有诸如“Name”、“Date”、“Foo”、“Bar”等键名,但在JSON对象出现之前,我们不知道它可能是什么。共同点是,knockout只需要显示JSON对象中的所有值。我也希望密钥可以被修复,但由于业务逻辑,可能会出现各种各样的密钥名称。@Wei:看到我的其他答案了吗。我保留了这个答案,因为我觉得这是解决这个问题的正确方法。因为您不能对JSON做任何事情,所以它不适用于您。但是其他人可能会觉得它很有用。嗨,我试着做同样的事情,用嵌套的表格格式显示它,在那里我们可以显示或隐藏孩子。你能帮我做吗?
[
  {
    "Text": "Hi",
    "Children": [
      {
        "Text": "Hello",
        "Children": [
          {
            "Text": "Bye"
          }
        ]
      }
    ]
  }
]
/* indent from second level only */
div.container div.container {
  margin-left: 10px;
}
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());
}
{
    "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>