在嵌套的foreach循环中递增计数器

时间:2016-06-29 04:51:28

标签: knockout.js

有没有办法从Knockout foreach绑定中手动增加ViewModel属性?

我想做一些逻辑上等同于:

的事情
var inc = 0;
for (var i = 0; i < 3; i++)
{
    for (var j = 0; j < 3; j++)
    {
        inc++;
        alert(inc + ': ' + i + ',' + j); // but write this to the dom
    }
} 

我曾尝试使用$index,但这只涉及当前循环,而不是内循环或父循环。

数组的大小可能不同,所以我不能简单地计算$parentContext.$index * [count of child items] + current $index

我想要实现的目标:

<div data-bind="foreach: Categories">
    <div data-bind="foreach: SubCategories" >
       <div data-bind="text: [someIncrementer] +': ' + $parent.Category + ',' + $data></div>
       <!-- should output: 
       1: A,1
       2: A,2 
       3: A,3  
       4: B,1
       5: B,3
       -->
    </div>
</div>
var ViewModel = function()
{
    var self = this;
    self.Categories = ko.observableArray([
       {Category: 'A', SubCategories: [1,2,3]}, 
       {Category: 'B', SubCategories: [1,3]}
    ]);
}

4 个答案:

答案 0 :(得分:2)

为其创建一个带有展平数组的计算observable:

var ViewModel = function() {
  var self = this;

  self.Categories = ko.observableArray([
    {Category: 'A', SubCategories: [1,2,3]}, 
    {Category: 'B', SubCategories: [1,3]}
  ]);

  self.FlattenedSubcategories = ko.computed(function() {
    var result = [], cats = self.Categories(), index = 1;
    for (var i = 0; i < cats.length; i++) {
      for (var j = 0; j < cats[i].SubCategories.length; j++) {
        result.push({
          Idx: index++,
          Category: cats[i].Category,
          Subcat: cats[i].SubCategories[j]
        });
      }
    }
    return result;
  });
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div data-bind="foreach: FlattenedSubcategories">
  <div>
    <span data-bind="text: Idx"></span>:
    <span data-bind="text: Category"></span>,
    <span data-bind="text: Subcat"></span>
  </div>
</div>

答案 1 :(得分:2)

不需要让它变得复杂得多。你可以尝试这样的事情:

&#13;
&#13;
var ViewModel = function() {
  var self = this;
  var index = 0;
  self.inc = function(val) {
    return ++index;
  }

  self.Categories = ko.observableArray([{
    Category: 'A',
    SubCategories: [1, 2, 3]
  }, {
    Category: 'B',
    SubCategories: [1, 3]
  }]);
};

ko.applyBindings(new ViewModel());
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: Categories">
  <!-- ko foreach: SubCategories -->
  <li>
    <span data-bind="text: $root.inc() + ': ' + $parent.Category + ', ' + $data"></span>
  </li>
  <!-- /ko -->
</ul>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

您可以将<ol> / <li>与数字计数器或CSS counter一起使用。

如果数字纯粹用于显示目的而且没有任何依赖于它,则此方法有效。

var ViewModel = function()
{
    var self = this;
    self.Categories = ko.observableArray([
       {Category: 'A', SubCategories: [1,2,3]}, 
       {Category: 'B', SubCategories: [1,3]},
       {Category: 'C', SubCategories: [7,8,9]},
       {Category: 'D', SubCategories: [10,11,12,13]}
    ]);
}

ko.applyBindings(new ViewModel());
.categories {
  counter-reset: category;
}
.subcategory::before {
  counter-increment: category;
  content: counter(category) ": ";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div class="categories" data-bind="foreach: Categories">
    <div data-bind="foreach: SubCategories">
        <div>
          <span class="subcategory" data-bind="text: $parent.Category + ',' + $data"></span>
        </div>
    </div>
</div>

答案 3 :(得分:0)

另一种选择:

就像你说的那样,knockout绑定上下文暴露了一个$index observable,它将索引保存在循环中。还有$parentContext来指代链中较高的上下文。

对于一个简单的2级嵌套循环,您可以创建一个帮助方法,该方法使用当前$index和父级$index来计算总索引:

// cIndex = current category's index
// sIndex = current subcategory's index
self.getSubIndex = function(cIndex, sIndex) {
  return sIndex + self.Categories
    .slice(0, cIndex)
    .reduce(function(count, c) {
      return count + c.SubCategories.length;
    }, 0);
}

写一下会有点烦人:

<span data-bind="text: $root.getSubIndex($parentContext.$index(), $index())">   </span>

您也可以传递$context并获取getSubIndex方法中的索引。您甚至可以递归地浏览上下文链,直到找不到$index属性为止。

就个人而言,我宁愿在index视图模型中创建一个SubCategory计算器,这会让人感觉不那么笨拙。但是,它需要SubCategory才能访问其父...

var ViewModel = function() {
  var self = this;
 

  self.Categories = ko.observableArray([{
    Category: 'A',
    SubCategories: [1, 2, 3]
  }, {
    Category: 'B',
    SubCategories: [1, 3]
  }]);
  
  self.getSubIndex = function(cIndex, sIndex) {
    return sIndex + self.Categories
      .slice(0, cIndex)
      .reduce(function(count, c) {
        return count + c.SubCategories.length;
      }, 0);
  }
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: Categories">
  <!-- ko foreach: SubCategories -->
  <li>
    <span data-bind="text: $root.getSubIndex($parentContext.$index(), $index()) + ': ' + $parent.Category + ', ' + $data"></span>
  </li>
  <!-- /ko -->
</ul>