使用 Can.js 创建分页对象
Creating a Pagination object with Can.js
我正在创建一个分页可观察对象。我用一个集合实例化它,它有一个派生的 paginatedList
,稍后我更新它的主列表(假设我已经过滤了数据)。显然,我希望派生列表能够识别并重新呈现视图,但事实并非如此。有些东西一定不能被束缚吧。
Here's a fiddle.
var Pagination = can.Map.extend({
pageNumber: 1,
pageSize: 10,
isFirstPage: can.compute(function() {
return this.attr('pageNumber') === 1;
}),
isLastPage: can.compute(function() {
return this.attr('pageNumber') === this.attr('lastPage');
}),
lastPage: can.compute(function() {
return Math.ceil(this.attr('list').attr('length') / this.attr('pageSize'));
}),
paginatedList: can.compute(function() {
var pgn = this.attr('pageNumber'),
pgs = this.attr('pageSize'),
start = (pgn-1) * pgs,
end = start + pgs;
return this.attr('list').slice(start, end);
}),
prevPage: function() {
if (!this.attr('isFirstPage'))
this.attr('pageNumber', this.pageNumber-1);
},
nextPage: function() {
if (!this.attr('isLastPage'))
this.attr('pageNumber', this.pageNumber+1);
},
toPage: function(pageNumber) {
this.attr('pageNumber', pageNumber);
}
});
var paginated = new Pagination({ list: collection });
...模板看起来像...
<table>
{{#paginated.paginatedList}}
<tr>
....
</tr>
{{/paginated.paginatedList}}
</table>
然后,稍后,用户过滤列表...
paginated.attr('list').replace(collection.filter(function() {
// return filtered collection
}))
但是视图没有重新呈现。什么没有绑定?
首先,尝试解释我认为在您的示例中发生的事情:
了解 can.compute 如何弄清楚如何 publish/emit 它发生了变化可能并不明显,但在您的示例中,计算 paginatedList
会发出它已经发生的事实当任何属性 pageNumber
、pageSize
或 list
更改时,您可以在使用 .attr()
访问器方法访问属性的计算中看到这一点。
can.List 中的 replace
方法替换列表 中的项目 而不是列表本身,因此
在这个例子中,.attr('list')
访问的 属性 实际上并没有改变(也没有
pageNumber
或 pageSize
), 它仍然是列表的同一个实例,只是有不同的项目
现在在里面,所以计算值不会更新,这反过来也不会更新模板。
作为对示例的 simple/naive 修复,您只需替换:
paginated.attr('list').replace(collection.filter(function() {
return Math.random() < 0.5;
}));
和
paginated.attr('list', collection.filter(function() {
return Math.random() < 0.5;
}));
...即替换整个列表,而不仅仅是列表中的项目。
这是一个 fiddle 的变化 http://jsfiddle.net/phx1jgq1/1/
当然这可能不是您要查找的内容,也许您实际上想要绑定到项目可能会更改的列表。
这里的问题是 this.attr('list').slice(start, end);
并没有真正绑定到列表的所有单个项目,而是类似于:
this.attr('list').filter(function(item, index){
return index >= start && index < end;
});
...确实如此,因此您只需替换该行即可使其按预期工作。
这是一个 fiddle 的变化:http://jsfiddle.net/n2tygdud/1/
当然,如果过滤所有项目感觉不对,您可能想查看 define plugin,让您制定高级和特定行为can.Maps 像 getter、setter 和类型转换,并使用它来绑定到列表 add/remove 事件并相应地更新计算的 属性。
我正在创建一个分页可观察对象。我用一个集合实例化它,它有一个派生的 paginatedList
,稍后我更新它的主列表(假设我已经过滤了数据)。显然,我希望派生列表能够识别并重新呈现视图,但事实并非如此。有些东西一定不能被束缚吧。
Here's a fiddle.
var Pagination = can.Map.extend({
pageNumber: 1,
pageSize: 10,
isFirstPage: can.compute(function() {
return this.attr('pageNumber') === 1;
}),
isLastPage: can.compute(function() {
return this.attr('pageNumber') === this.attr('lastPage');
}),
lastPage: can.compute(function() {
return Math.ceil(this.attr('list').attr('length') / this.attr('pageSize'));
}),
paginatedList: can.compute(function() {
var pgn = this.attr('pageNumber'),
pgs = this.attr('pageSize'),
start = (pgn-1) * pgs,
end = start + pgs;
return this.attr('list').slice(start, end);
}),
prevPage: function() {
if (!this.attr('isFirstPage'))
this.attr('pageNumber', this.pageNumber-1);
},
nextPage: function() {
if (!this.attr('isLastPage'))
this.attr('pageNumber', this.pageNumber+1);
},
toPage: function(pageNumber) {
this.attr('pageNumber', pageNumber);
}
});
var paginated = new Pagination({ list: collection });
...模板看起来像...
<table>
{{#paginated.paginatedList}}
<tr>
....
</tr>
{{/paginated.paginatedList}}
</table>
然后,稍后,用户过滤列表...
paginated.attr('list').replace(collection.filter(function() {
// return filtered collection
}))
但是视图没有重新呈现。什么没有绑定?
首先,尝试解释我认为在您的示例中发生的事情:
了解 can.compute 如何弄清楚如何 publish/emit 它发生了变化可能并不明显,但在您的示例中,计算 paginatedList
会发出它已经发生的事实当任何属性 pageNumber
、pageSize
或 list
更改时,您可以在使用 .attr()
访问器方法访问属性的计算中看到这一点。
can.List 中的 replace
方法替换列表 中的项目 而不是列表本身,因此
在这个例子中,.attr('list')
访问的 属性 实际上并没有改变(也没有
pageNumber
或 pageSize
), 它仍然是列表的同一个实例,只是有不同的项目
现在在里面,所以计算值不会更新,这反过来也不会更新模板。
作为对示例的 simple/naive 修复,您只需替换:
paginated.attr('list').replace(collection.filter(function() {
return Math.random() < 0.5;
}));
和
paginated.attr('list', collection.filter(function() {
return Math.random() < 0.5;
}));
...即替换整个列表,而不仅仅是列表中的项目。
这是一个 fiddle 的变化 http://jsfiddle.net/phx1jgq1/1/
当然这可能不是您要查找的内容,也许您实际上想要绑定到项目可能会更改的列表。
这里的问题是 this.attr('list').slice(start, end);
并没有真正绑定到列表的所有单个项目,而是类似于:
this.attr('list').filter(function(item, index){
return index >= start && index < end;
});
...确实如此,因此您只需替换该行即可使其按预期工作。
这是一个 fiddle 的变化:http://jsfiddle.net/n2tygdud/1/
当然,如果过滤所有项目感觉不对,您可能想查看 define plugin,让您制定高级和特定行为can.Maps 像 getter、setter 和类型转换,并使用它来绑定到列表 add/remove 事件并相应地更新计算的 属性。