【发布时间】:2014-04-06 10:00:50
【问题描述】:
我无法使用 Ember Data,因为我们的数据模型有点复杂(例如,并非所有东西都有 id),而且我不喜欢缓存和其他一些东西;但是,我确实喜欢它的模型具有状态标志(isNew、isDeleting),所以我正在尝试实现一些功能。
基本要点是,无论何时从服务器检索模型,该数据都存储在 _data 对象中。每当用户随后更改某物的值时,该值都存储在 _attributes 对象中。通过比较两者,我可以看到模型是否脏。属性是用 app.attr 方法定义的。
app.Person = app.Model.extend({
"id": app.attr("number"),
"name": app.attr("string"),
"age": app.attr("number")
});
attr 函数与 ember data 的非常相似。
function getValue(record, key, options) {
var attrs = get(record, "_attributes"),
data = get(record, "_data");
if ( attrs.hasOwnProperty(key) ) {
return attrs[key];
} else if ( data.hasOwnProperty(key) ) {
return data[key];
} else if ( typeof options.defaultValue === "function" ) {
return options.defaultValue();
}
return options.defaultValue; // may be undefined
}
app.attr = function(type, options) {
options = options || {};
var meta = {
"type": type,
"isAttribute": true,
"options": options
};
return function(key, value) {
if ( arguments.length > 1 ) {
if ( key === "id" ) {
console.error("id is readonly on "+this.constructor.toString());
} else {
if ( get(this, "_data."+key) === value ) {
delete get(this, "_attributes")[key]; // not sure if this really works? seems to from my testing. set(this, "_attributes."+key, undefined) literally set undefined, which did not work
} else {
set(this, "_attributes."+key, value);
}
}
}
return getValue(this, key, options);
}.property("_data").meta(meta);
};
然后在我的模型上,我有某些标志,例如 isNew 和 isDirty。 isDirty 是一个计算属性是有意义的,但它需要在任何属性更改时进行更新。我想也许 .property("_attributes.*") 会这样做,但事实并非如此。我难住了。我尝试将其设置为 volatile.. 这可确保在明确要求时获得正确的值,但模板不会在基础属性更改时更新。
对于我上面的模型,执行 .property("id", "name", "age") 是合适的,但这些会因模型而异。我能够在模型的 init 中获取当前模型的属性,但我找不到动态更改它们的方法。
这是我的模型:
app.Model = Ember.Object.extend({
"_attributes": null,
"_data": null,
"isDeleted": false,
"isNew": false,
"isSaving": false,
"isDirty": function() {
var attrs = get(this, "_attributes");
for ( k in attrs ) {
if ( attrs.hasOwnProperty(k) ) {
return true;
}
}
return false;
}.property("_attributes").readOnly(), // NOTE: not quite right
"init": function() {
this._super();
set(this, "_data", {});
set(this, "_attributes", {});
var attrs = [];
this.constructor.eachAttribute(function(name, meta) {
attrs.push(name);
});
// NOTE: Can I do anything to attach all the attrs to isDirty here?
}
});
app.Model.reopenClass({
"attributes": Ember.computed(function() {
var map = Ember.Map.create();
this.eachComputedProperty(function(name, meta) {
if ( meta.isAttribute ) {
meta.name = name;
map.set(name, meta);
}
});
return map;
}),
"eachAttribute": function(callback, binding) {
get(this, "attributes").forEach(function(name, meta) {
callback.apply(binding, arguments);
}, binding);
}
});
我用代码和测试创建了一个 jsFiddle:http://jsfiddle.net/2uCn3/3/
所以知道如何让 isDirty 在属性更改时进行更新吗? 同样(如在 jsFiddle 中所见),如果 _data.someProperty 直接更改,则 attr 仍将返回旧的默认值,因此我也对其进行了测试..但本质上是相同的问题。
我考虑过使用像 _attributesChanged 这样的计数器并使用 incrementProperty,但它看起来并不可靠而且看起来很糟糕。
我还考虑将 _attributes 和 _data 转换为数组,然后 @each 可能会有一些用处。
希望有更清洁的方法。我仍在试图弄清楚 ember 数据是如何做到的。
更新:我发现如果您直接操作 _data.property,Ember Data 也会出现错误,我想出了一个解决方法,但 GJK 的解决方案要好得多。
【问题讨论】:
标签: javascript ember.js