如何仅加载集合的字段的子集/在主详细信息场景中具有延迟模型字段/惰性嵌套集合?

时间:2013-04-04 23:53:32

标签: backbone.js

我对Backbone相对较新,我已经搜索了一段时间,并没有找到满足我的问题的答案(这个问题很接近,但不确定它是否完全适用Backbone.js Master-Detail scenario)< / p>


tl; dr:如何表示集合中的子集(如在集合的某些模型的字段中,而不是在分页/过滤中的子集)? (例如,列表视图仅显示某些内容的名称和修改日期,当详细信息不仅包含更多字段,还包括嵌套子集合时)


现在到详细版本,这是应用程序的结构:

模型

  • DocumentCollection - 文档集合,应仅提取名称和上次修改日期
    • Document - 当作为集合提取的一部分被提取时,应仅提取名称和修改日期,当获取“独立”时(例如在详细信息视图中)也应该获取描述和子文章
      • ArticleColletion作为Document一部分的嵌套集合,只应在文档在详细信息视图中获取时获取,但应该是“懒惰”并且在获取DocumentCollection时不会获取
        • Article

观看次数

  • DocumentCollectionView(仅显示文档名称和上次修改日期)
  • DocumentView(包括文档名称,说明和文章)
  • ArticlesViewArticleView用于展示单个或一组文章

目标

我希望DocumentCollection fetch方法调用仅带来Document模型的子集(仅限名称和修改时间), 并且在直接获取Document时,也可以获取描述字段和子文章

真实世界模型有更复杂,有更多字段,所以我需要在线上削减一些流量,而不是在需要之前加载字段或子集合。

可能的解决方案

  1. 覆盖fetch方法,并应用相关逻辑(例如“完整”或“部分”加载的标志)

  2. 忘记惰性字段,只使嵌套集合变得懒惰,剪切未使用的字段是过早的和不必要的优化,并不是模型决定需要什么以及什么不是视图渲染的一部分的重新定义,它应该全部带来

  3. 为“摘要”视图设置不同的集合和模型,例如DocumentSummaryCollection并将DocumentCollection扩展为DocumentSummaryCollection

  4. 问题

    上述内容(如果有的话)是“骨干”方式吗?还有其他方法吗?

2 个答案:

答案 0 :(得分:8)

这是常见的情况之一,我不确定是否存在“骨干”方式。这是一种可能的解决方案......

当你获取文档集合(/api/documents)时,你会返回一些像这样的json:

[{id: 1, name: 'foo'}, {id: 2, name: 'bar'}]

当您获取文档(/api/documents/1)时,返回一些像这样的json:

{
    id: 1, name: 'foo', description: 'some stuff about foo', 
    articles: [{id: 1, name: 'hello'}, {id: 2, name: 'hi again'}]
}

当获取单个DocumentModel时,将有一个新属性articles。您监听change:articles事件,并set将新json转换为this.articles,这是一个ArticlesCollection。

现在......一些代码:

var Article = Backbone.Model.extend({});

var ArticleCollection = Backbone.Collection.extend({
    model: Article
});

var Document = Backbone.Model.extend({
    constructor: function() {
        // make sure articles collection is created.
        this.articles = new ArticleCollection();
        Backbone.Model.prototype.constructor.apply(this, arguments);
    },
    initialize: function(attributes, options) {
        this.articlesChanged();
        this.on('change:articles', this.articlesChanged, this);
    },

    // articles attribute changed.
    // set it into the Collection.
    // this way, existing models will be updated, new ones added.
    articlesChanged: function(){
        // if document was fetched and has articles json array,
        // set that json into this.articles collection.
        var articles = this.get('articles');
        if(articles){
            this.articles.set(articles);
            // remove 'articles' attribute now that it is set into the collection.
            this.unset('articles');
        }
    }
});

var DocumentCollection = Backbone.Collection.extend({
    model: Document
});

更多代码:

var docs = new DocumentCollection();
docs.fetch().done(function() {
    // docs now has documents with only name, date attributes, 
    // and empty articles collection.
    var doc = docs.at(0);
    var name = doc.get('name'); // foo
    var articleCount = doc.articles.length; // 0

    doc.fetch().done(function() {
        // first doc is now full, with articles, description, etc.
        doc.articles.each(function(article) { 
            console.log(article.get('name'));
        }, this);

        // re-fetch the collection later... to check if new documents exist.
        docs.fetch().done(function() {
            // new docs added, removed docs gone.
            // existing doc models updated.
        });
    });
});

我认为我最喜欢的是,它保留了文档/文章集合实例,即使文档集合或稍后重新获取单个文档也是如此。

因此,例如,如果您在详细信息视图中显示了DocumentModel及其文章集合,并且重新获取了整个DocumentCollection,则在获取后显示的DocumentModel仍将位于集合中(除非它实际上是在服务器上删除)。如果您将某些change add remove类型的事件连接到这些实例,那就太好了。

随着Backbone 1.0向'更新'提取(这很棒),我很好奇是否还有其他(或更好的)解决方案,因为这确实是一个非常常见的问题...我真的没有太多使用这个确切的解决方案,我不确定它是否理想。我过去常常使用parse来抓取子json和reset子集合。但是我觉得我在更新fetch时遇到了一些问题,所以开始尝试这个。

答案 1 :(得分:0)

我会构建我的服务,只返回你需要的字段,并使用骨干文档中的集合的parse方法。

    parsecollection.parse(response, options) 
只要服务器在fetch中返回集合的模型,Backbone就会调用

parse。该函数传递给原始响应对象,并应返回要添加到集合中的模型属性数组。默认实现是无操作,只是通过JSON响应。如果您需要使用预先存在的API,或者更好地命名您的响应,请覆盖此项。

在parse函数中,您可以迭代响应并使用返回的propeties构建模型(id必须在返回的属性中),然后可以在需要时使用完整模型获取这些模型。