我无法使用Ember数据,因为我们的数据模型有点复杂(例如,并非所有东西都有一个ID),我不喜欢缓存和其他一些关于它的事情;然而,我确实喜欢它的模型有状态标志(isNew,isDeleting),所以我试图实现一些功能。如何在动态子属性更改时更新Ember计算属性
基本要点是,无论何时从服务器检索模型,该数据都存储在_data对象中。每当用户更改某个值时,它就存储在_attributes对象中。通过比较两者,我可以看到模型是否脏。属性使用app.attr方法定义。
app.Person = app.Model.extend({
"id": app.attr("number"),
"name": app.attr("string"),
"age": app.attr("number")
});
attr函数与ember数据非常相似。
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。*”)会这样做,但它不。我很难过。我试图让它挥发..这确保我得到正确的值时明确要求它,但模板不会更新时,底层属性更改。
对于我上面的模型,可以使用.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的解决方案无限更好。