107

我有一个关于 Backbone.js 的getset函数的简单问题。

1) 使用下面的代码,如何直接“获取”或“设置”obj1.myAttribute1?

另一个问题:

2) 在模型中,除了默认对象之外,我可以/应该在哪里声明模型的其他属性,以便可以通过 Backbone 的 get 和 set 方法访问它们?

var MyModel = Backbone.Model.extend({
    defaults: {
        obj1 : {
            "myAttribute1" : false,
            "myAttribute2" : true,
        }
    }
})

var MyView = Backbone.View.extend({
    myFunc: function(){
        console.log(this.model.get("obj1"));
        //returns the obj1 object
        //but how do I get obj1.myAttribute1 directly so that it returns false?
    }
});

我知道我可以做到:

this.model.get("obj1").myAttribute1;

但这是好的做法吗?

4

9 回答 9

145

虽然this.model.get("obj1").myAttribute1很好,但这有点问题,因为那时你可能会想为 set 做同样类型的事情,即

this.model.get("obj1").myAttribute1 = true;

但是,如果您这样做,您将无法获得 Backbone 模型的好处myAttribute1,例如更改事件或验证。

更好的解决方案是永远不要在模型中嵌套 POJSO(“普通旧 JavaScript 对象”),而是嵌套自定义模型类。所以它看起来像这样:

var Obj = Backbone.Model.extend({
    defaults: {
        myAttribute1: false,
        myAttribute2: true
    }
});

var MyModel = Backbone.Model.extend({
    initialize: function () {
        this.set("obj1", new Obj());
    }
});

然后访问代码将是

var x = this.model.get("obj1").get("myAttribute1");

但更重要的是设置代码是

this.model.get("obj1").set({ myAttribute1: true });

这将触发适当的更改事件等。这里的工作示例:http: //jsfiddle.net/g3U7j/

于 2011-06-14T23:44:12.337 回答
75

我为此创建了主干深度模型- 只需扩展 Backbone.DeepModel 而不是 Backbone.Model,然后您就可以使用路径来获取/设置嵌套模型属性。它也维护更改事件。

model.bind('change:user.name.first', function(){...});
model.set({'user.name.first': 'Eric'});
model.get('user.name.first'); //Eric
于 2011-11-05T13:57:43.683 回答
16

Domenic 的解决方案可以工作,但是每个新的 MyModel 都将指向同一个 Obj 实例。为避免这种情况,MyModel 应如下所示:

var MyModel = Backbone.Model.extend({
  initialize: function() {
     myDefaults = {
       obj1: new Obj()
     } 
     this.set(myDefaults);
  }
});

有关完整说明,请参阅 c3rin 的回答 @ https://stackoverflow.com/a/6364480/1072653

于 2012-02-19T23:16:05.293 回答
5

我使用这种方法。

如果您有这样的 Backbone 模型:

var nestedAttrModel = new Backbone.Model({
    a: {b: 1, c: 2}
});

您可以使用以下方式设置属性“ab”:

var _a = _.omit(nestedAttrModel.get('a')); // from underscore.js
_a.b = 3;
nestedAttrModel.set('a', _a);

现在您的模型将具有以下属性:

{a: {b: 3, c: 2}}

触发“更改”事件。

于 2013-03-06T18:11:23.707 回答
3

有一种没有人想到的解决方案可以使用很多。您确实不能直接设置嵌套属性,除非您使用您可能不想要的第三方库。但是,您可以做的是克隆原始字典,在那里设置嵌套属性,然后设置整个字典。小菜一碟。

//How model.obj1 looks like
obj1: {
    myAttribute1: false,
    myAttribute2: true,
    anotherNestedDict: {
        myAttribute3: false
    }
}

//Make a clone of it
var cloneOfObject1 = JSON.parse(JSON.stringify(this.model.get('obj1')));

//Let's day we want to change myAttribute1 to false and myAttribute3 to true
cloneOfObject1.myAttribute2 = false;
cloneOfObject1.anotherNestedDict.myAttribute3 = true;

//And now we set the whole dictionary
this.model.set('obj1', cloneOfObject1);

//Job done, happy birthday
于 2016-08-22T13:57:54.083 回答
2

@pagewil 和@Benno 对@Domenic 的解决方案有同样的问题。我的答案是编写一个简单的 Backbone.Model 子类来解决问题。

// Special model implementation that allows you to easily nest Backbone models as properties.
Backbone.NestedModel = Backbone.Model.extend({
    // Define Backbone models that are present in properties
    // Expected Format:
    // [{key: 'courses', model: Course}]
    models: [],

    set: function(key, value, options) {
        var attrs, attr, val;

        if (_.isObject(key) || key == null) {
            attrs = key;
            options = value;
        } else {
            attrs = {};
            attrs[key] = value;
        }

        _.each(this.models, function(item){
            if (_.isObject(attrs[item.key])) {
                attrs[item.key] = new item.model(attrs[item.key]);
            }
        },this);

        return Backbone.Model.prototype.set.call(this, attrs, options);
    }
});

var Obj = Backbone.Model.extend({
    defaults: {
        myAttribute1: false,
        myAttribute2: true
    }
});

var MyModel = Backbone.NestedModel.extend({
    defaults: {
        obj1: new Obj()
    },

    models: [{key: 'obj1', model: Obj}]
});

NestedModel 为您做的是允许这些工作(当 myModel 通过 JSON 数据设置时会发生这种情况):

var myModel = new MyModel();
myModel.set({ obj1: { myAttribute1: 'abc', myAttribute2: 'xyz' } });
myModel.set('obj1', { myAttribute1: 123, myAttribute2: 456 });

在初始化时自动生成模型列表很容易,但这个解决方案对我来说已经足够好了。

于 2012-07-26T17:29:24.127 回答
2

Domenic 提出的解决方案有一些缺点。假设您想收听“更改”事件。在这种情况下,不会触发“初始化”方法,并且您的属性自定义值将替换为来自服务器的 json 对象。在我的项目中,我遇到了这个问题。我覆盖模型的“设置”方法的解决方案:

set: function(key, val, options) {
    if (typeof key === 'object') {
        var attrs = key;
        attrs.content = new module.BaseItem(attrs.content || {});
        attrs.children = new module.MenuItems(attrs.children || []);
    }

    return Backbone.Model.prototype.set.call(this, key, val, options);
}, 
于 2015-08-29T16:26:07.867 回答
1

虽然在某些情况下使用 Backbone 模型而不是嵌套的 Object 属性是有意义的,正如 Domenic 所提到的,但在更简单的情况下,您可以在模型中创建一个 setter 函数:

var MyModel = Backbone.Model.extend({
    defaults: {
        obj1 : {
            "myAttribute1" : false,
            "myAttribute2" : true,
        }
    },
    setObj1Attribute: function(name, value) {
        var obj1 = this.get('obj1');
        obj1[name] = value;
        this.set('obj1', obj1);
    }
})
于 2015-06-02T22:40:13.140 回答
0

如果您与后端交互,则需要具有嵌套结构的对象。但是骨干更容易使用线性结构。

骨干.线性可以帮助你。

于 2015-07-21T01:08:22.407 回答