Создание объекта пагинации с помощью 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, и использовать его для привязки к список добавляет / удаляет события и обновляет вычисляемое свойство соответственно.

Другие вопросы по тегам