Backbone.js 获取和设置嵌套对象属性

发布于 2024-11-15 08:28:04 字数 843 浏览 3 评论 0原文

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

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

另一个问题:

2)在模型中,除了 defaults 对象之外,我可以/应该在哪里声明模型的其他属性,以便可以通过 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;

但是这是好的做法吗?

I have a simple question about Backbone.js' get and set functions.

1) With the code below, how can I 'get' or 'set' obj1.myAttribute1 directly?

Another question:

2) In the Model, aside from the defaults object, where can/should I declare my model's other attributes, such that they can be accessed via Backbone's get and set methods?

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?
    }
});

I know I can do:

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

but is that good practice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

飘然心甜 2024-11-22 08:28:04

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

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

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

更好的解决方案是永远不要在模型中嵌套 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/

While this.model.get("obj1").myAttribute1 is fine, it's a bit problematic because then you might be tempted to do the same type of thing for set, i.e.

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

But if you do this, you won't get the benefits of Backbone models for myAttribute1, like change events or validation.

A better solution would be to never nest POJSOs ("plain old JavaScript objects") in your models, and instead nest custom model classes. So it would look something like this:

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

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

Then the accessing code would be

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

but more importantly the setting code would be

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

which will fire appropriate change events and the like. Working example here: http://jsfiddle.net/g3U7j/

别低头,皇冠会掉 2024-11-22 08:28:04

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

model.bind('change:user.name.first', function(){...});
model.set({'user.name.first': 'Eric'});
model.get('user.name.first'); //Eric

I created backbone-deep-model for this - just extend Backbone.DeepModel instead of Backbone.Model and you can then use paths to get/set nested model attributes. It maintains change events too.

model.bind('change:user.name.first', function(){...});
model.set({'user.name.first': 'Eric'});
model.get('user.name.first'); //Eric
山田美奈子 2024-11-22 08:28:04

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以获得完整的解释。

Domenic's solution will work however each new MyModel will point to the same instance of Obj.
To avoid this, MyModel should look like:

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

See c3rin's answer @ https://stackoverflow.com/a/6364480/1072653 for a full explanation.

水溶 2024-11-22 08:28:04

我使用这种方法。

如果您有这样的 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}}

触发“change”事件。

I use this approach.

If you have a Backbone model like this:

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

You can set the attribute "a.b" with:

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

Now your model will have attributes like:

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

with the "change" event fired.

天涯沦落人 2024-11-22 08:28:04

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

//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

There is one solution nobody thought of yet which is lots to use. You indeed can't set nested attributes directly, unless you use a third party library which you probably don't want. However what you can do is make a clone of the original dictionary, set the nested property there and than set that whole dictionary. Piece of cake.

//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
怕倦 2024-11-22 08:28:04

我对 @Domenic 的解决方案遇到了 @pagewil 和 @Benno 相同的问题。我的答案是编写一个简单的 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 为您做的就是允许这些工作(这就是通过 JSON 数据设置 myModel 时发生的情况):

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

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

I had the same problem @pagewil and @Benno had with @Domenic's solution. My answer was to instead write a simple sub-class of Backbone.Model that fixes the problem.

// 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}]
});

What NestedModel does for you is allow these to work (which is what happens when myModel gets set via JSON data):

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

It would be easy to generate the models list automatically in initialize, but this solution was good enough for me.

半暖夏伤 2024-11-22 08:28:04

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

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);
}, 

Solution proposed by Domenic has some drawbacks. Say you want to listen to 'change' event. In that case 'initialize' method will not be fired and your custom value for attribute will be replaced with json object from server. In my project I faced with this problem. My solution to override 'set' method of Model:

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);
}, 
飘逸的'云 2024-11-22 08:28:04

虽然在某些情况下使用 Backbone 模型而不是嵌套对象属性是有意义的,如 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);
    }
})

While in some cases using Backbone models instead of nested Object attributes makes sense as Domenic mentioned, in simpler cases you could create a setter function in the model:

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);
    }
})
北城挽邺 2024-11-22 08:28:04

如果与后端交互,则需要具有嵌套结构的对象。
但有了主干,更容易与线性结构一起工作。

backbone.linear 可以帮助你。

If you interact with backend, which requires object with nesting structure.
But with backbone more easy to work with linear structure.

backbone.linear can help you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文