KnockoutJS按项目类别显示排序列表

时间:2014-05-31 20:38:37

标签: javascript jquery knockout.js

本周我刚刚开始学习淘汰赛,除了这一个问题,一切都很顺利。

我有一个项目列表,我按多种方式排序,但我想要排序的方式之一需要具有与标准列表不同的显示。举个例子,假设我有这个代码

var BetterListModel = function () {
var self = this;
food = [
{
    "name":"Apple",
    "quantity":"3",
    "category":"Fruit",
    "cost":"$1",
},{
    "name":"Ice Cream",
    "quantity":"1",
    "category":"Dairy",
    "cost":"$6",
},{
    "name":"Pear",
    "quantity":"2",
    "category":"Fruit",
    "cost":"$2",
},{
    "name":"Beef",
    "quantity":"1",
    "category":"Meat",
    "cost":"$3",
},{
    "name":"Milk",
    "quantity":"5",
    "category":"Dairy",
    "cost":"$4",
}];
self.allItems = ko.observableArray(food); // Initial items                                            
// Initial sort
self.sortMe = ko.observable("name");
ko.utils.compareItems = function (l, r) {
    if (self.sortMe() =="cost"){
        return l.cost > r.cost ? 1 : -1 
    } else if (self.sortMe() =="category"){
        return l.category > r.category ? 1 : -1
    } else if (self.sortMe() =="quantity"){
        return l.quantity > r.quantity ? 1 : -1
    }else {
        return l.name > r.name ? 1 : -1 
    }   

};
};
ko.applyBindings(new BetterListModel());

和HTML      

<p>Your values:</p>
<ul class="deckContents" data-bind="foreach:allItems().sort(ko.utils.compareItems)">
    <li><div style="width:100%"><div class="left" style="width:30px" data-bind="text:quantity"></div><div class="left fixedWidth" data-bind="text:name"></div> <div  class="left fixedWidth" data-bind="text:cost"></div> <div  class="left fixedWidth" data-bind="text:category"></div><div style="clear:both"></div></div></li>
</ul>
<select data-bind="value:sortMe">
    <option selected="selected" value="name">Name</option>
    <option value="cost">Cost</option>
    <option value="category">Category</option>
    <option value="quantity">Quantity</option>
</select>
</div>

所以我可以通过任何字段对它们进行排序,我可以按名称对它们进行排序,它会显示类似的内容

3 Apple $1 Fruit
1 Beef $3 Meat
1 Ice Cream $6 Dairy
5 Milk $4 Dairy
2 Pear $2 Fruit

这是我到目前为止的一个小提琴http://jsfiddle.net/Darksbane/X7KvB/

除了类别排序外,此显示适用于所有排序。我想要的是当我按类别对它们进行排序以显示它时

Fruit
3 Apple $1 Fruit
2 Pear $2 Fruit

Meat
1 Beef $3 Meat

Dairy
1 Ice Cream $6 Dairy
5 Milk $4 Dairy

有没有人知道我怎么能够以这种不同的方式显示它?

2 个答案:

答案 0 :(得分:5)

  • 您的观点不应包含超出渲染所需的逻辑。因此,您的foreach绑定 data-bind="foreach:allItems().sort(ko.utils.compareItems)"应该成为computed可观察的。

  • 您应该将<option>数据移到模型中并利用options数据绑定。

要解决实际问题,您将利用template绑定和containerless if绑定。

template绑定将允许您根据所选的排序类型更改视图的外观。因此可以使用2个模板,default-template处理常规显示,category-template专门用于基于类别的渲染。

<script type="text/html" id="category-template">
 <ul class="deckContents" data-bind="foreach:sortedItems">
     <li>
         <!-- ko if: $root.outputCategory($index()) -->
         <div data-bind="text:category"></div>
         <!-- /ko -->
          <span class="indented" data-bind="text:name"></span> 
          <span  class="indented" data-bind="text:cost"></span> 
          <span  class="indented" data-bind="text:category"></span>
     </li>
 </ul>

html用法:<div data-bind='template: { name: currentTemplate, data: $data}'></div>其中currentTemplate是一个计算的observable,它根据排序类型返回模板ID。

您必须以某种方式为类别指定优先级。我这样做是通过声明var categoryPriority = ["Fruit", "Meat", "Dairy"]

看看my fiddle我没有解决fixedWidth使用的default-template,因此您需要处理CSS样式以便按照您想要的方式排列。 < / p>

修改有没有办法动态地将项目添加到列表中并让它自动显示在排序列表中?

  1. 推出一个新项目:当您想要淘汰时,&#34;通知&#34;在执行推送之前,您不希望使用readallItems() observableArray。相反,您将使用allItems.push推入observableArray,这反过来将导致敲除触发computed observables(依赖于此可观察对象)来评估,subscriptions执行,DOM要更新的元素......等等。

  2. 计算的依赖关系:为了计算到&#34;依赖&#34;在另一个可观察对象上,它必须在提供的求值函数内部read。因为sortedItems只读取sortType这是唯一的&#34;触发器&#34;重新评估。因此,将allItems.sort更改为allItems().sort会导致sortedItemsallItems发生更改时进行评估。

  3. 请参阅How Dependency Tracking Works

答案 1 :(得分:0)

通过使用排序方法,我们可以按升序对列表进行排序 我正在举例并解释这一点。

food = [{
    "name":"Apple",
    "quantity":"3",
    "category":"Fruit",
    "cost":"$1",
},{
    "name":"Ice Cream",
    "quantity":"1",
    "category":"Dairy",
    "cost":"$6",
},{
    "name":"Pear",
    "quantity":"2",
    "category":"Fruit",
    "cost":"$2",
},{
    "name":"Beef",
    "quantity":"1",
    "category":"Meat",
    "cost":"$3",
},{
    "name":"Milk",
    "quantity":"5",
    "category":"Dairy",
    "cost":"$4",
}];
self.allItems = ko.observableArray(food); 

这里有一个数组。通过使用以下代码对此列表进行排序

self.allItems.sort(function (left, right) {
    return left.name() == right.name() ? 0 : (left.name() < right.name() ? -1 : 1)
});

如果你想按成本排序,那就明智了..就是这样。将名称更换为cost..u就可以得到它。