我有以下问题:我有一个可观察的数组(从服务器填充),如下所示:
this.elems = ko.observableArray([
{n: 1, t : 'hello'},
{n: 1, t : 'why'},
{n: 1, t : 'are'},
{n: 2, t : 'some'},
{n: 2, t : 'ducks'},
{n: 3, t : 'here'},
{n: 8, t : '?'}
]);
我希望以下列方式展示它:
1
Hello
why
are
2
some
ducks
3
here
8
?
如您所见,仅当前一个数字与当前数字不同时才显示数字。
使用foreach
绑定(这是我的jsFiddle)非常容易。
<div data-bind="foreach: elems">
<div class="t1">
<span data-bind="text: n" class="c1"></span>
<span data-bind="text: t" class="c2"></span>
</div>
</div>
只有我能够访问先前的元素。 我知道我可以修改我的observalbe数组并实现我想要的,但有没有办法在不改变它的情况下做到这一点?
答案 0 :(得分:7)
您可以访问$ index和$ parent值。试试这个:
<div data-bind="foreach: elems">
<div class="t1">
<!-- ko if: $index() === 0 || $parent.elems()[$index() - 1].n !== n -->
<span data-bind="text: n" class="c1"></span>
<!-- /ko -->
<span data-bind="text: t" class="c2"></span>
</div>
</div>
使用可见绑定的替代方法:
<div data-bind="foreach: elems">
<div class="t1">
<span data-bind="text: n, visible: $index() === 0 || $parent.elems()[$index() - 1].n !== n" class="c1"></span>
<span data-bind="text: t" class="c2"></span>
</div>
</div>
答案 1 :(得分:2)
如果elems
属性是动态加载的,我建议您使用computed
observable对数据进行分组,并返回包含这些组的数组。
因此,给定以下简单的分组功能:
function groupArray(array, keyRetrieverFunc){
var groupedArray = array.reduce(function(previous, item){
var key = keyRetrieverFunc(item);
if (previous[key]){
previous[key].items.push(item);
} else {
previous[key] = { key: key, items: [
item
]};
}
return previous;
}, {});
return groupedArray
}
我们可以创建一个如下所示的viewmodel:
function ViewModel(){
var self = this;
self.elems = ko.observableArray([
{n: 1, t : 'hello'},
{n: 1, t : 'why'},
{n: 1, t : 'are'},
{n: 2, t : 'some'},
{n: 2, t : 'ducks'},
{n: 3, t : 'here'},
{n: 8, t : '?'}
]);
self.groupedElements = ko.computed(function(){
var groups = {};
var elements = self.elems();
var groups = groupArray(elements, function(item){return item.n;});
var results = [];
for(var property in groups){
results.push(groups[property]);
}
return results;
});
}
观察groupsElements computed
可观察对象。这是我们将DOM元素绑定到的可观察对象。
<div data-bind="foreach: groupedElements">
Group name: <span data-bind="text: key"></span>
<div data-bind="foreach: items">
<div data-bind="text: t"></div>
</div>
</div>
当新数据进入并替换观察到的self.elems
数组时,groupedElements
将自动更新,因为computed
observable已订阅self.elems
数组中的更改
我在小提琴http://jsfiddle.net/J6k54/处设置了他的设置。
答案 2 :(得分:1)
一个。您必须更改viewmodel的结构 喜欢:
function AppViewModel() {
this.elems = ko.observable([
{n: 1, t : ['hello','why']},
{n: 2, t : ['why','not']},
]);
}
ko.applyBindings(new AppViewModel());
B中。你的html bindins将是:
<div data-bind="foreach: elems">
<div class="t1" >
<span data-bind="text: n" class="c1"></span>
<span data-bind="foreach: t">
<br/>
<span data-bind="text: $data" class="c2"></span>
</span>
</div>
答案 3 :(得分:1)
我认为你正在寻找这个:
<div data-bind="foreach: elems">
<div class="t1">
<!-- ko if: ($index() === 0
|| ($parent.elems()[$index()-1].n != $parent.elems()[$index()].n)) -->
<span data-bind="text: n" class="c1"></span>
<!--/ko-->
<span data-bind="text: t" class="c2"></span>
</div>
</div>
参见 fiddle
答案 4 :(得分:0)
实现此目的的最简单方法是使用underscore.js转换数据结构
看到这个小提琴 http://jsfiddle.net/62Fz8/9/
underscore.js中的转换函数非常简单:
_.chain(self.elems())
.groupBy(function (o) { return o.n; })
.map(function (o, key) { return { n: key,t: o };}).value();
将此函数包装在ko.computed函数中并直接绑定到它。 这会将您的数组转换为一个简单的分组,然后您需要的是以下数据绑定:
<h1> What I you want to achieve </h1>
<div data-bind="foreach: groupedItems">
<div class="t1">
<span data-bind="text: n" class="c1"></span>
<!--ko foreach:t -->
<span data-bind="text: t" class="c2"></span>
<!-- /ko -->
</div>
</div>