使用Can.js创建分页对象

时间:2015-05-18 20:26:07

标签: javascript canjs

我正在创建一个分页可观察对象。我用一个集合实例化它,它有一个派生的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
}))

但视图不会重新渲染。什么不受约束?

1 个答案:

答案 0 :(得分:1)

首先,尝试解释我认为你的例子中发生的事情:

了解can.compute如何确定如何发布/发出它已经发生了变化可能并不明显,但在您的示例中,计算paginatedList将发出它在任何属性时已更改的事实pageNumberpageSizelist更改,您可以在计算机中看到使用.attr()访问器方法访问属性的内容。

can.List中的replace方法替换列表中的而不是列表本身,所以 在这个例子中,.attr('list')访问的属性实际上并没有改变(也没有 pageNumberpageSize),它仍然是列表的相同实例,它只有不同的项目 现在,因此计算出的值不会更新,而后者又不会更新模板。

作为示例的简单/天真修复,您只需替换:

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/

当然,如果过滤所有项目感觉不对,您可能需要查看 define plugin ,让您将高级和特定行为映射到can.Maps就像getter,setter和type conversion,并使用它来绑定到列表添加/删除事件并相应地更新计算属性。