简体   繁体   中英

Displaying nested JSON as nested list using knockout.js

I have a nested JSON like this:

[
    {
        "Run 1": {
            "1.2.0": {
                "Server": {
                    "TestSuite 1": [
                        {
                            "version": "1.2.0",
                            "type": "server",
                            "testdef": "TestSuite 1",
                            "testcaseid": "TestCase 1",
                            "status": "pass"
                        },
                        {
                            "version": "1.2.0",
                            "type": "server",
                            "testdef": "TestSuite 1",
                            "testcaseid": "TestCase 2",
                            "status": "fail"
                        }
                    ],
                    "TestSuite 2": [
                        {
                            "version": "1.2.0",
                            "type": "server",
                            "testdef": "TestSuite 2",
                            "testcaseid": "TestCase 1",
                            "status": "pass"
                        }
                    ]
                }
            }
        }
    }
]

I want to display it on the html page as an unordered list like this: 项目符号列表

but I am seeing the last item repeated multiple times:

在此处输入图片说明

This is html with knockout.js bindings:

<div class="row">
  <div class="tree">
    <ul data-bind="foreach: {data: testResults, as: 'item'}">
      <li data-bind="foreach: {data: Object.keys(item), as: 'key'}"><span data-bind="text: 'Run' + key"></span>
        <ul data-bind="foreach: {data: item[key], as: 'item2'}" class="child">
          <li data-bind="foreach: {data: Object.keys(item2), as: 'key2'}"><span data-bind="text: key2"> </span>
            <ul data-bind="foreach: {data: item2[key2], as: 'item3'}" class="child">
              <li data-bind="foreach: {data: Object.keys(item3), as: 'key3'}"><span data-bind="text: key3"> </span>
                <ul data-bind="foreach: {data: item3[key3], as: 'item4'}" class="child">
                  <li data-bind="foreach: {data: Object.keys(item4), as: 'key4'}"><span data-bind="text: key4"> </span>
                    <ul data-bind="foreach: {data: item4[key4], as: 'item5'}" class="child">
                      <li data-bind="foreach: {data: Object.keys(item5), as: 'key5'}"><span data-bind="text: item5.testcaseid, css : {'bg-success' : item5.status == 'pass', 'bg-danger' : item5.status == 'fail'}"> </span><br></li>
                    </ul>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</div>

testResults is a ko.observableArray() in my view model which contains the above JSON.

What would be the correct way to display the leaf elements only once

The problem is you're nesting so many foreach bindings that you're getting lost in how many nested loops there are. Your last look at the very end is not needed. You loop through the keys of the test suite objects when you don't need to. Remove that last foreach binding.

<ul data-bind="foreach: {data: item4[key4], as: 'item5'}" class="child">
    <li>
        <span data-bind="text: item5.testcaseid,
                         css : {'bg-success' : item5.status == 'pass',
                                'bg-danger' : item5.status == 'fail'}">
        </span><br>
    </li>
</ul>

Don't do this. Do you really want to have to look at that view and try to maintain that?

I have two suggestions, either map the results out to arrays and foreach over those or iterate over the properties alone with the help of custom bindings to make it more manageable. You can use this foreachprop binding handler to do this:

<ul data-bind="foreach: testResults">
    <li data-bind="foreachprop: $data"><span data-bind="text: key"></span>
        <ul data-bind="foreachprop: value">
            <li><span data-bind="text: key"></span>
                <ul data-bind="foreachprop: value">
                    <li><span data-bind="text: key"></span>
                        <ul data-bind="foreachprop: value">
                            <li><span data-bind="text: key"></span>
                                <ul data-bind="foreach: value">
                                    <li><span data-bind="text: testcaseid"></span></li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM