admin管理员组

文章数量:1403522

I have a multidimensional associative array.

this.items = ko.observableArray([
    { name: "name1", viewable: true, children: [
        { name: "name1-1", viewable: true, children: []},
        { name: "name1-2", viewable: false, children: []}
    ] },
    { name: "name2", viewable: false, children: [] },
    { name: "name3", viewable: true, children: [
        { name: "name3-1", viewable: true, children: []},
    ] },
        { name: "name4", viewable: true, children: [] }
]);

The goal is to loop through this array and print out only the values that have 'viewable' set to true.

I have this working using a bunch of if and foreach statements, but the code is starting to get out of hand. This example only covers 2 levels buy my array can get up to 5 levels deep, so this code is going to multiply and get ugly really quick.

<ul data-bind="foreach: items">
    <!-- ko if: viewable -->
    <li data-bind="text: name"></li>
        <!-- ko foreach: children -->
            <!-- ko if: viewable -->
            <li data-bind="text: name"></li>
            <!-- /ko -->
        <!-- /ko -->
    <!-- /ko -->
</ul>

So is there an easier/better way to loop through the entire array?

JS Fiddle link

I have a multidimensional associative array.

this.items = ko.observableArray([
    { name: "name1", viewable: true, children: [
        { name: "name1-1", viewable: true, children: []},
        { name: "name1-2", viewable: false, children: []}
    ] },
    { name: "name2", viewable: false, children: [] },
    { name: "name3", viewable: true, children: [
        { name: "name3-1", viewable: true, children: []},
    ] },
        { name: "name4", viewable: true, children: [] }
]);

The goal is to loop through this array and print out only the values that have 'viewable' set to true.

I have this working using a bunch of if and foreach statements, but the code is starting to get out of hand. This example only covers 2 levels buy my array can get up to 5 levels deep, so this code is going to multiply and get ugly really quick.

<ul data-bind="foreach: items">
    <!-- ko if: viewable -->
    <li data-bind="text: name"></li>
        <!-- ko foreach: children -->
            <!-- ko if: viewable -->
            <li data-bind="text: name"></li>
            <!-- /ko -->
        <!-- /ko -->
    <!-- /ko -->
</ul>

So is there an easier/better way to loop through the entire array?

JS Fiddle link

Share Improve this question edited Apr 4, 2013 at 15:22 dmathisen asked Apr 4, 2013 at 14:50 dmathisendmathisen 2,3425 gold badges37 silver badges65 bronze badges 2
  • Do you have a proper resursive sturture? E.g. the items looks like the same on each level? In your sample some children are missing like: { name: "name1-1", viewable: true}, is this a requirement? – nemesv Commented Apr 4, 2013 at 15:19
  • Oh, that's a typo. I can control that, so I figure that it's best to include 'children', even if it's empty. I edited my code and added children to all items. So, yes, all items will look the same on all levels. – dmathisen Commented Apr 4, 2013 at 15:23
Add a ment  | 

3 Answers 3

Reset to default 3

Underscore.js has some nice method working with arrays maybe you can use flatten and filter to create one array from your structure then you can just write one foreach:

Or you could use templates to encapsulate your if: viewable logic and apply the template recursively:

<script type="text/html" id="template">
  <!-- ko if: viewable -->
    <li data-bind="text: name"></li>    
        <!-- ko template: { name: 'template', foreach: $data.children } -->
        <!-- /ko -->    
  <!-- /ko -->
</script>

<ul data-bind="template: { name: 'template', foreach: items } ">
</ul>

Demo JSFiddle.

What you need is a template:

<script type="text/html" id="ItemTemplate">
    <!-- ko if: viewable -->
        <li data-bind="text: name"></li>
        <!-- ko template: { name: 'ItemTemplate', foreach: children } --><!-- /ko -->
    <!-- /ko -->
</script>

And then just:

<ul data-bind="template: { name: 'ItemTemplate', foreach: items }"></ul>

If you add empty children arrays on items you can use template

JSFiddle sample

<ul data-bind="foreach: items">
    <idv data-bind="template: {name: 'mytemp'}" />
</ul>
<div data-bind="stopBinding:true">
    <div id="mytemp">
        <div data-bind="visible :viewable">
            <li data-bind="text: name"></li>
            <div data-bind="foreach: children">
                <div data-bind="template: {name: 'mytemp'}" /></div>
        </div>
    </div>
</div>

本文标签: javascriptWorking with Knockout 39foreach39 looping through multidimensional arrayStack Overflow