Backbone.js获取并设置嵌套的对象属性
我有一个关于Backbone.js的get和set函数的简单问题。
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;
但这是一个好的做法吗?
虽然this.model.get("obj1").myAttribute1
问题,但有点问题,因为那样你可能会试图做同样types的事情,
this.model.get("obj1").myAttribute1 = true;
但是,如果你这样做,你不会得到myAttribute1
的Backbone模型的好处,比如更改事件或validation。
更好的解决scheme是永远不要在你的模型中嵌套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/
我为此创build了骨干深度模型 – 只需扩展Backbone.DeepModel而不是Backbone.Model,然后就可以使用path获取/设置嵌套的模型属性。 它也保持更改事件。
model.bind('change:user.name.first', function(){...}); model.set({'user.name.first': 'Eric'}); model.get('user.name.first'); //Eric
Domenic的解决scheme将工作,但每个新的MyModel将指向相同的Obj实例。 为了避免这种情况,MyModel应该看起来像这样:
var MyModel = Backbone.Model.extend({ initialize: function() { myDefaults = { obj1: new Obj() } this.set(myDefaults); } });
有关完整的解释,请参阅c3rin的答案@ https://stackoverflow.com/a/6364480/1072653 。
我使用这种方法。
如果你有这样一个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}}
随着“改变”事件被解雇。
@pagewil和@Benno与@ Domenic的解决scheme有同样的问题。 我的答案是,而不是写一个简单的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 });
在初始化时自动生成模型列表会很容易,但是这个解决scheme对我来说已经足够了。
Domenic提出的解决scheme有一些缺点。 假设你想听“改变”事件。 在这种情况下,“初始化”方法将不会被触发,您的属性的自定义值将被服务器的json对象replace。 在我的项目中,我遇到了这个问题。 我的解决scheme覆盖模型的“设置”方法:
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); },
有一个解决scheme没有人想到哪个是很多使用。 你的确不能直接设置嵌套的属性,除非你使用了你可能不需要的第三方库。 然而,你可以做的是做一个原始字典的克隆,在那里设置嵌套属性,并设置整个字典。 小菜一碟。
//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
虽然在某些情况下,使用Backbone模型而不是嵌套的Object属性是有道理的,但在更简单的情况下,您可以在模型中创build一个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); } })
如果您与后端进行交互,需要嵌套结构的对象。 但是骨干更容易与线性结构一起工作。
backbone.linear可以帮助你。
- hibernateexception:org.hibernate.AnnotationException:没有为实体指定标识符:com..domain.idea.MAE_MFEView
- 隐藏ipython中的所有警告