2013-02-14 59 views
0

想象一下按姓名排序的联系人数组。 这个阵列可以像被输出:在foreach循环中分配值

<ul data-bind="foreach: contacts> 
    <li data-bind="text: name"></li> 
</ul> 

我想要做的是指定具有不同的起始字母每个L1的前进方向,所以例如显示A,B,d ...

- A 
- Anderson 
- Andrews 
- B 
- Bellamy 
- D 
- Davidson 
- Davis 

在正常的编程语言,我会定义一个变量包含名称的第一个字母,并检查foreach循环里面,看它是否是不同的。如果是这种情况,请显示标题。

我应该如何用knockout.js做到这一点?

回答

1

这里的那支淘汰赛模式的方法。首先,您将创建一个计算的观察值,将您的数组映射到按字母分组的新数组中。

self.contactsByLetter = ko.computed(function() { 
    var result = [], 
     currentLetter, currentGroup; 
    ko.utils.arrayForEach(self.contacts(), function (contact) { 
     if (contact.name[0] !== currentLetter) { 
      currentLetter = contact.name[0]; 
      currentGroup = { 
       letter: currentLetter, 
       contacts: [] 
      } 
      result.push(currentGroup); 
     } 
     currentGroup.contacts.push(contact); 
    }) 
    return result; 
}); 

然后你的HTML只需要两个循环。

<ul data-bind="foreach: contactsByLetter"> 
    <li class="heading" data-bind="text: letter"></li> 
    <!--ko foreach: contacts--> 
    <li data-bind="text: name"></li> 
    <!--/ko--> 
</ul> 

的jsfiddle:http://jsfiddle.net/mbest/ZcQT4/

0

不知道它是清洁的方式,但你可以使用一个固定的数组的字母,然后在您的视图模型的方法只返回开头的第n个字母的项目 - 即

<ul data-bind="foreach: letters"> 
    <li data-bind="text: $data"> 
     <ul data-bind="foreach: $parent.contactsStartingWith($data)"> 
      <li data-bind="text: name"></li> 
     </ul> 
    </li> 
</ul> 

哪里contactsStartingWith可以像来定义:

function(start) { 
    return ko.utils.arrayFilter(contacts(), function(it) { return it.name()[0].toUpperCase() == start }); 
} 

...和字母阵列可以容易地提取为:

viewModel.letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); 

(用于处理数组淘汰赛utils的一些有用的参考资料:http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html

+0

我认为迈克尔的建议是更好,因为它也将避免“空”的标题。例如。如果没有与第一个字母Q的联系。感谢您的回复。 – 2013-02-15 07:29:45

+0

我同意,它也更容易处理(所有东西都捆绑在一个可观察对象内) - 事实上,我也投了赞成票:) – Grim 2013-02-15 08:20:08