使用knockout js在foreach中添加类别

时间:2017-01-13 10:28:36

标签: javascript html knockout.js

我有一个装满文件的阵列。此文档包含一些类别,并按类别排序。对于每个类别,我希望有一个标题,如: - 运动 --- SportDocument 1 --- SportDocument 2 --- SportDocument 3 - 锦标赛 --- TournamentDocument 1 --- TournamentDocument 2 --- TournamentDocument 3

所以类别" Sport"和#"锦标赛"是标题。

我的问题是,我不知道如何使用此标题创建新的Div以获得列表。

我当前的代码



var DocumentRow = function (documentLine) {
    var self = this;
    // getting name and ID of the document
    self.Name = ko.observable(documentLine.Name);
    self.DocumentId = ko.observable(documentLine.DocumentId);

    // creating downloadLink
    self.DocumentLink = ko.computed(function () {
        return "someUrlPath/read/import/" + self.DocumentId();
    });
}




GetCustomerDocuments(data.SomeID)
                    .done(function (data) {
                        // Reset Documents from Previous View
                        self.documentLines([]);
  
                        // Only mapping when it has some data
                        if (data !== null && data !== undefined && data.length > 0) {
                            // loop trought the arry
                            self.documentLines(data.map(function (doc) {
                                return new DocumentRow(doc);
                            }));
                        }
                    })

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: documentLines">
  <div class="importDocument">
    <a data-bind="attr: {href: DocumentLink}, target:'_blank'">
      <span data-bind="target:'_blank'">
        <img src="../images/pdf.png" title="Document" />
      </span>
      <span data-bind="text: Name, target:'_blank'" title="Document"></span>
    </a>
  </div>
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

生成易于读取的数据绑定的简洁解决方案是创建ko.computed,为您的数据添加分组图层。你要创建这个结构:

  • documentLines
    • documentGroup
      1. documentRow
      2. documentRow
      3. ...
    • documentGroup
      1. ...

计算使用您的documentLines数组作为起点,为其遇到的每个唯一Category创建一个组,并将与此类别匹配的文档推送到该组。

您尚未显示实际的Category属性,因此我假设它是每个documentRow内的字符串属性。

下面的代码显示了分组计算机如何工作的示例。查看评论以获得有关正在发生的事情的解释。通过属性对对象进行分组是常见的事情,stackoverflow上应该有许多其他示例,向您展示如何进行操作。这更多关于淘汰赛如何运作:

var VM = function() {
  var self = this;
  
  // This is our data source
  self.documentRows = ko.observableArray([]);
  
  // This injects a group layer and will be used in our foreach:
  self.docGroups = ko.pureComputed(function() {
    // This creates a subscription that makes sure the object is updated
    // every time the documentRows are updated
    var rows = self.documentRows();
    
    // Grouping logic: 
    //  create an object of: { "CategoryName": [ /* documentRows*/ ] }
    var categoryMap = rows.reduce(function(map, row) {
      var category = row.Category;
      map[category] = map[category] || [];
      map[category].push(row);
      return map;
    }, {});
    
    // Transform to object and sort by name
    return Object.keys(categoryMap)
      .map(function(k) {
        return { name: k, rows: categoryMap[k] }
      })
      .sort(function(c1, c2) {
        return c1.name.localeCompare(c2.name);
      });
  });
}

var vm = new VM();
ko.applyBindings(vm);

vm.documentRows.push({Category: "Cat1", Text: "The First Document"});
vm.documentRows.push({Category: "Cat2", Text: "The Second Document"});
vm.documentRows.push({Category: "Cat2", Text: "The Second 2nd Document"});
vm.documentRows.push({Category: "Another category", Text: "The Third Document"});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<h2>Categories:</h2>
<ul data-bind="foreach: docGroups">
  <li>
    <h3 data-bind="text: name"></h3>
    <ul data-bind="foreach: rows">
      <li data-bind="text: Text"></li>
    </ul>
  </li>
</ul>
                   

其他方法:

如果您不想要嵌套结构,您还可以创建一个包含两种类型对象的平面列表:文档和组。您必须使用iftemplate绑定来确定您希望如何呈现它。

如果您确定您的数据是按分组属性排序的,那么可以通过检查$parent.documentLines()[$index() - 1].Category === $data.Category来创建视图中是否需要类别标签的逻辑,但我强烈反对这个建议......