我想保存对我服务器的通话,因此我目前正在使用Model.save()
patch
选项并发送changedAttributes()
。
我想删除一个属性并添加一个新属性。 Model.set()
/ unset()
每次都会修改changedAttributes()
,因此我无法将其与上述Model.save()
/ patch
方案一起使用。
我想我只想简单地调用Model.set()
并传入一个对象,其中包含我希望设置为undefined
的值以及我想要设置的值。
有没有办法让unset()
和set()
一起去changedAttributes()
?或者可能为一组操作确定changedAttributes()
?
// Currently
var m = new Backbone.Model({ "foo": "bar" });
m.unset("foo");
console.log(m.changedAttributes()); // { "foo": undefined }
m.set("baz", "bar");
console.log(m.changedAttributes()); // { "baz": "bar" }
console.log(m.attributes); // { "baz": "bar" }
// At this point, how do I get the combination of changed attributes? something like: { "foo": undefined, "baz": "bar" }?
// Is that even possible? Am I doing something horribly wrong?
//================================================================
// What (I think) I want is for Model.set() to remove attributes with values of undefined, so I only have to make one call and changedAttributes() will be pristine. Maybe with a option or something?
var w = new Backbone.Model({ "foo": "bar" });
w.set({ "foo": undefined, "baz": "bar" });
console.log(w.changedAttributes()); // { "foo": undefined, "baz": "bar" }
console.log(w.attributes); // I would like it to be { "baz": "bar" }, "foo" having been removed in the set() call.
//================================================================
// I was trying to avoid processing the objects by hand. I realize that I can do something like the following.
var h = new Backbone.Model({ "foo": "bar" });
var changes = { "foo": undefined, "baz": "bar" };
_.each(changes, function(val, key) {
if (_.isUndefined(val)) {
h.unset(key, { "silent": true });
} else {
h.set(key, val, { "silent": true });
}
});
h.trigger('change'); // Trigger a change event after all the changes have been done.
console.log(changes); // { "foo": undefined, "baz": "bar" }
console.log(h.attributes); // { "baz": "bar" }
上述代码的小提琴:http://jsfiddle.net/clayzermk1/AmBfh/
一年前似乎就这个话题进行了一些讨论https://github.com/documentcloud/backbone/pull/879。似乎我想要的功能在某些时候存在。
编辑:正如@ dennis-rongo指出的那样,我显然可以手工做到这一点。重述上面的问题:“Backbone是否允许一次设置/删除属性?”如果没有,这个决定背后的理由是什么? Derick Bailey创建了Backbone.Memento(https://github.com/derickbailey/backbone.memento)来处理属性状态,Backbone上有几个关于与这种情况密切相关的模型状态的问题(https://github.com/documentcloud/backbone/pull/2360,有点相关:https://github.com/documentcloud/backbone/issues/2316,高度相关:https://github.com/documentcloud/backbone/issues/2301)。
编辑2:我不是在寻找手动解决方案,我可以制作它或多或少地做我想做的事情(参见上面的示例代码)。 我正在寻找当前设计的理由,为这个常见场景提供一个干净的例子 - 一次性设置和取消设置。
更新:https://github.com/documentcloud/backbone/issues/2301中有关于此主题的一些对话。我提交了一个拉取请求(https://github.com/documentcloud/backbone/pull/2368),试图鼓励讨论当前的实施。
感谢所有发布回答的人!
答案 0 :(得分:1)
有很多方法可以修饰这个!所以,我会集中讨论您提问的部分问题:
有没有办法让
unset()
和set()
一起去changedAttributes()
?
因为我认为这是去这里的方式。
Backbone.Model.unset()
只是Backbone.Model.set()
的别名。来自消息来源:
unset: function(attr, options) {
return this.set(attr, void 0, _.extend({}, options, {unset: true}));
},
那么为什么不做m.set({"baz": "bar", "foo": void 0});
呢?看到我从你的这个小提琴:http://jsfiddle.net/dimadima/Q8ZuV/。从那里粘贴,结果将是
console.log(m.changedAttributes()); // { "baz": "bar", "foo": undefined }
console.log(m.attributes); // // {foo: undefined, baz: "bar"}, unfortunately "foo"is not deleted
所以m.attributes
有点偏,因为您未设置的密钥未被删除,但您可以对其进行测试。
无论如何,我建议略读Backbone.Model.set()
的来源,以了解您的其他选择。如果你愿意,我可以详细说明。
答案 1 :(得分:0)
这样的事情应该有效。
基本上循环遍历无效的所有属性和unset
属性(伪造和非布尔值)。
/** Create a Model and set attributes */
var President = Backbone.Model.extend({});
var m = new President({first: 'Abraham', last: 'Lincoln', age: 90});
/** Blank out an attribute or two */
m.set({age: ''});
/** Loop through each attributes and unset falsy ones.
Also pass in silent = true so it doesn't trigger a change event
(in case you have listeners).
*/
_.each(m.toJSON(), function(val, col){
if (typeof val !=='boolean' && !val) {
m.unset(col, {silent: true});
}
}, this);
/** Output the new Model */
console.log(m.toJSON());
或强>
如果您想转向那个方向,则可以创建一个仅包含已更改属性的新Model
。
var President = Backbone.Model.extend({});
var m = new President({
first: 'Abraham', last: 'Lincoln', age: 90, registered: true});
/** Blank out or change an attribute or two */
m.set({first: null});
/** Pass changed attributes to a new Model */
var t = new President();
if (!_.isEmpty(m.changedAttributes())) {
_.each(m.changedAttributes(), function(val, col) {
t.set(col, val);
}, this);
}
答案 2 :(得分:0)
当前实现将允许您调用set()
并传入具有混合属性的对象来设置和取消设置。要有效取消设置属性,请为其指定undefined
的值。密钥将保留在模型的attributes
哈希中,但只要模型序列化为JSON,undefined
值就不会出现在序列化中(这是由于{{的实现) 1}})。它不会JSON.stringify()
来自模型的属性。
MDN - JSON - stringify中描述了delete
序列化中删除JSON.stringify()
值的行为:
如果在转换过程中遇到未定义,函数或XML值,则将其省略(在对象中找到它)或删除为null(在数组中找到它时)。
我没有为我的特定情况(BSON)使用JSON序列化,所以我最终不得不为自己手动编写解决方案。
我用拉取请求对GitHub进行了讨论,最终决定保持API原样。有关详细信息,请参阅此拉取请求:https://github.com/documentcloud/backbone/pull/2368。
再次感谢所有参与讨论的人,包括SO和GH。