在集合上设置属性 - 主干 js

Posted

技术标签:

【中文标题】在集合上设置属性 - 主干 js【英文标题】:Setting attributes on a collection - backbone js 【发布时间】:2011-08-21 07:12:33 【问题描述】:

主干js中的集合不允许你set属性,但我经常发现需要存储一些关于集合的元信息。设置该信息的最佳位置在哪里?

【问题讨论】:

我没有用过 Backbone,所以评论而不是回答:看起来 Backbone 集合是 javascript 对象(很难想象它们还会是什么),这意味着除非它们是 @ 987654322@(一个新的 ECMAScript5 东西),如果您愿意,可以按常规方式向它们添加属性:instance.prop = value;。当然,您必须小心不要使用与对象上已经存在的任何内容冲突的名称... 答案完全取决于它是什么样的元信息。根据您的存储内容,它可能适合收藏或视图。 @T.J. Crowder - 我可以这样做,但它有很多潜在的问题。我认为,拥有一个仅用于属性的专用对象意味着您可以更安全。 我将创建一个将集合作为属性的对象。 【参考方案1】:

我已经阅读了其他答案和 cmets,虽然我很欣赏将集合包装在模型中的想法可能是绝对最干净的方式,但我发现 99.9% 的时间它绝对是矫枉过正的。 Backbone 为 IMO 提供了 initialize 钩子来实现这个目的。

const FooCollection = Backbone.Collection.extend(
    initialize: function(models, attributes) 
        attributes.log && console.log('foo!');  // Or set attributes on 'this', etc
    
);

// Passing null for first arg, which is optionally an array of models
// to initialize the collection with
const fooCollection = new FooCollection(null,  log: true  );

多年来一直这样做,从未遇到任何问题/缺点。

【讨论】:

这很好用 Madbreaks,毫无疑问。我避免使用此解决方案的原因是因为我希望能够使用 fetch 而无需修改。看看这个问题,它更详细地解释了我所说的:***.com/questions/5931898/…【参考方案2】:

最好完全按照预期的方式使用 Collection:作为一组模型。 (Julien 已经在 OP 上评论了这个,我想解释一下为什么我认为他是对的)

假设您正在考虑书籍(模型)的库(集合),如 Backbone 的文档示例中所示。有意义的是,您已经获得了有关要存储的图书馆的元信息,例如该图书图书馆所在的地址。

诀窍是不要将其视为元信息。您的图书馆有很多属性,其中一个属性就是它的藏书。

var Book = Backbone.Model.extend( 
    title: "Moby Dick"
);

var Collection = Backbone.Collection.extend(
    model: Book
);

var Library = 
    address: '45th Street',
    collection: Collection
;

在本例中,我将库定义为纯 JavaScript 对象。显然,您也可以让 Library 成为一个模型,以便它拥有所有 Backbone 的花里胡哨。 我的观点是,您需要以一种更现实的方式来表示现实,方法是退后一步,看到您想要分配给 Collection 的额外属性实际上是上一层对象的兄弟属性:在这种情况下是 Library .


【讨论】:

感谢您提供更好的答案。我发布了一个单独的问题,这对我来说很明显。 ***.com/questions/5931898/…我鼓励任何人阅读该问题中的对话;我发现它非常清晰。 @Wytze : 如果我将库声明为另一个主干模型是否正确? OP 的问题对于构造 fetch() 使用的 url 所必需的 API 密钥、用户 ID 等内容似乎很重要。 在上面的例子中,假设我有一个 Book 视图,它还应该显示这本书当前所在的地址。你会怎么做? this.model.collection.owner.address 之类的东西?我不太喜欢。【参考方案3】:

我已经通过事件触发升级了 Raynos 的方法,因此我们可以绑定到集合的属性更新。

cls.groups = Backbone.Collection.extend(

    // ...

    // Reference to this collection's model.
    model: cls.group,

    initialize: function() 
        this._attributes = 
    ,

    // Extend collection with ability to store attributes and trigger events on attributes changing
    attr: function(prop, value) 
        if (value === undefined) 
            return this._attributes[prop]
         else 
            this._attributes[prop] = value;
            this.trigger('change:' + prop, value);
        
    ,

    // ...

);


cls.group = Backbone.View.extend(

    // ...

    initialize: function() 

        // Catching attribute update
        app.groups.on('change:selected', function(value) 
            // ...
        , this);
    ,

    // ...

    events: 
        'click' : function(e) 
            // Set collection meta attribute on model's view click event
            app.groups.attr('selected', this.model.cid);
        
    

    // ...

);

【讨论】:

看看这个问题的替代方案。从本质上讲,将集合包装在模型中可以提供更大的灵活性,而不会在集合中添加大量垃圾。 ***.com/questions/5931898/…【参考方案4】:

只需.extend 具有元数据存储功能的集合。

var MyCollection = Backbone.Collection.extend(
    initialize: function() 
        ...

        this._meta = ;
    ,
    model: ...
    meta: function(prop, value) 
        if (value === undefined) 
            return this._meta[prop]
         else 
            this._meta[prop] = value;
        
    ,
);

var collection = new MyCollection();
collection.add(someModels);
collection.meta("someProperty", value);

...

var value = collection.meta("someProperty");

可能有更好的地方存储特定元数据,但这完全取决于元数据是什么。

为了存储通用元数据,使用一种方法来扩展你的集合构造函数来处理它应该可以工作。

请注意,如果需要从服务器存储和加载此元数据,那么您将面临更大的任务。

【讨论】:

谢谢你 - 帮助很大。你的最后一点也突出了我一直想做的事情......不过,我会问另一个问题,因为你的回答正是我一直想要的。 @idbentley 如果您确切地强调需要持久存储的元数据是什么,我可以为您指明正确的方向。 我在这里问了一个新问题,详细信息:***.com/questions/5931898/… 事实证明这并不是最好的方法。相反,将集合包装在模型中。事实上,如果我当时仔细阅读了文档,我会知道这一点,因为他们在这里举了一个例子:documentcloud.github.com/backbone/#FAQ-nested。元信息存在于包装模型中。这应该会有所帮助。 meta 函数贡献不大。您可以直接使用 _meta(view._meta.a = 'b'var c = view._meta.a)。除此之外,@idbentley 的评论是一个更好的解决方案。【参考方案5】:

使用@Raynos 解决方案的函数meta 只有一个参数对我不起作用。所以我使用了以下代码:

var MyCollection = Backbone.Collection.extend(
    initialize: function() 
        this._meta = ;
    ,
    put: function(prop, value) 
        this._meta[prop] = value;
    ,
    get: function(prop) 
        return this._meta[prop];
    
);

var collection = new MyCollection();
collection.put("someProperty", 12);
alert(collection.get("someProperty"));

希望它会有所帮助。

【讨论】:

它不起作用的原因是因为有一个错误。 !== 而不是 ===

以上是关于在集合上设置属性 - 主干 js的主要内容,如果未能解决你的问题,请参考以下文章

从主干集合加载完整日历事件会破坏下一个和上一个函数

如何使用模型/集合获取 4 个 JSON (API) 响应到主干.js 中的一个视图

在主干中渲染集合模型

如何使用 StickIt 从主干中绑定长度。集合?

过滤主干集合返回一个模型数组

svn常用快捷命令集合。