Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 动态子特性更改时如何更新Ember computed特性_Javascript_Ember.js - Fatal编程技术网

Javascript 动态子特性更改时如何更新Ember computed特性

Javascript 动态子特性更改时如何更新Ember computed特性,javascript,ember.js,Javascript,Ember.js,我不能使用Ember数据,因为我们的数据模型有点复杂(例如,不是所有的东西都有id),我不喜欢缓存和其他一些东西;然而,我确实喜欢它的模型有状态标志(isNew,isDeleting),所以我尝试实现一些功能 基本要点是,无论何时从服务器检索模型,数据都存储在_数据对象中。当用户更改某个值时,该值存储在_attributes对象中。通过比较两者,我可以看出模型是否脏。属性是使用app.attr方法定义的 app.Person = app.Model.extend({ "id": app.at

我不能使用Ember数据,因为我们的数据模型有点复杂(例如,不是所有的东西都有id),我不喜欢缓存和其他一些东西;然而,我确实喜欢它的模型有状态标志(isNew,isDeleting),所以我尝试实现一些功能

基本要点是,无论何时从服务器检索模型,数据都存储在_数据对象中。当用户更改某个值时,该值存储在_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(“\u 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);
    }
});
我用代码和测试创建了一个JSFIDLE:

那么,知道如何在属性更改时让isDirty更新吗? 类似地(如JSFIDLE中所示),如果直接更改了_data.someProperty,attr仍将返回旧的默认值,因此我也对此进行了测试。。但本质上是同一个问题

我曾考虑过使用类似于_attributesChanged的计数器并使用incrementProperty,但它似乎不可靠,看起来很糟糕

我还考虑将_属性和_数据转换为数组,然后@each可能会有一些用处

希望有一个更干净的方法。我仍在试图弄清楚余烬数据是如何做到这一点的


更新:我发现如果你直接操作一个_Data.property,Ember数据也会有bug,我已经想出了一个解决办法,但GJK的解决方案要好得多。

我也为Ember编写了自己的持久层,解决方法是调用
this.notifyPropertyChange(“_attributes”)
每次我更改
\u属性时。我看不到您的所有代码,但是如果您将编辑
\u attributes
限制为仅使用几个mutator方法,那么您应该只需要在3或4个位置调用它。然后,对于您的计算属性,您可以让它依赖于
\u属性
属性

在代码中,只需在
attr
函数中的两个位置调用它就足够了。(假设这是修改
\u属性
内容的唯一方法)


我也为Ember编写了自己的持久层,解决方法是每次更改
\u attributes
对象时调用
this.notifyPropertyChange(“\u attributes”)
。我看不到您的所有代码,但是如果您将编辑
\u attributes
限制为仅使用几个mutator方法,那么您应该只需要在3或4个位置调用它。然后,对于您的计算属性,您可以让它依赖于
\u属性
属性

在代码中,只需在
attr
函数中的两个位置调用它就足够了。(假设这是修改
\u属性
内容的唯一方法)

 if ( get(this, "_data."+key) === value ) {
    delete get(this, "_attributes")[key];
    this.notifyPropertyChange('_attributes');
 } else {
    set(this, "_attributes."+key, value);
    this.notifyPropertyChange('_attributes');
 }