Создание объекта пагинации с помощью Can.js
Я создаю наблюдаемый объект пагинации. Я создаю его экземпляр с помощью коллекции, и она имеет производную paginatedList
и через некоторое время я обновляю его основной список (скажем, я отфильтровал данные). Очевидно, я хочу, чтобы производный список распознал это и перерисовал представление, но это не так. Что-то не должно быть связано правильно. Вот скрипка
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
}))
Но вид не перерисовывает. Что не связано?
1 ответ
Итак, во-первых, попытка объяснить, что, по моему мнению, происходит в вашем примере:
Понимание того, как can.compute вычисляет, как опубликовать / издать его, может быть неочевидным, но в вашем примере вычисления paginatedList
, будет излучать тот факт, что он изменился, когда любое из свойств pageNumber
, pageSize
, или же list
изменение, вы можете увидеть это в вычислении, с помощью которого свойства доступны с помощью .attr()
метод доступа.
replace
Метод в списке can.List заменяет элементы в списке, а не сам список, поэтому в этом примере свойство, к которому обращается .attr('list')
на самом деле не меняется (и при этом pageNumber
или же pageSize
), это все тот же экземпляр списка, в котором теперь есть разные элементы, поэтому вычисленное значение не обновляется, что, в свою очередь, не обновляет шаблон.
В качестве простого / наивного исправления примера вы можете просто заменить:
paginated.attr('list').replace(collection.filter(function() {
return Math.random() < 0.5;
}));
с
paginated.attr('list', collection.filter(function() {
return Math.random() < 0.5;
}));
... то есть, заменяя весь список, а не только элементы в списке.
Вот скрипка с этим изменением http://jsfiddle.net/phx1jgq1/1/
Конечно, это может быть не то, что вы ищете, возможно, вы действительно хотите привязать список, где элементы могут измениться. Проблема здесь в том, что this.attr('list').slice(start, end);
на самом деле не привязывается ко всем отдельным элементам списка, но что-то вроде:
this.attr('list').filter(function(item, index){
return index >= start && index < end;
});
... так что вы можете просто заменить эту строку, чтобы она работала так, как вы ожидаете.
Вот скрипка с этим изменением: http://jsfiddle.net/n2tygdud/1/
Конечно, если фильтрация по всем элементам не кажется нужной, вы, вероятно, захотите заглянуть в плагин определения, который позволит вам отображать расширенные и специфические поведения для can.Map, таких как getters, setters и translation type, и использовать его для привязки к список добавляет / удаляет события и обновляет вычисляемое свойство соответственно.