以角度观察复杂对象层次结构的深度和内容

时间:2016-11-02 13:22:56

标签: javascript angularjs json

我正在尝试编写一些代码来检测角度中复杂嵌套的分层对象的更改。我希望$watch$watchCollection表达式就足够了,但事实证明这很难实现。

有人可以提出一个解决问题的好方法吗?

我期待观察的数据结构的一个例子是(在json中):

{
    "$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
    "Name":"DevelopmentEnvironment",
    "Descendents":{
        "$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]][], VM.ConfigurationServer",
        "$values":[{
            "$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
            "Name":"MoreSpecificEnvironment",
            "Descendents":{
                "$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]][], VM.ConfigurationServer",
                "$values":[{
                    "$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
                    "Name":"level3",
                    "Descendents":null
                }]
            }
        }]
    }
}

如您所见,Json Serializer的TypeNameHandling设置为All,这是系统其他部分所必需的。

我需要注意的是,对任何嵌套对象的Name属性进行了任何更改,并添加或删除了Descendent

我试过了两次

scope.$watch(<objectname>, function(){...}, true);

scope.watchCollection(<objectname>, function(){...}, true);

这两个属性都会检测顶级NameDescendents属性的更改,但对于嵌套的对象没有任何更改。

根据我的理解,这表明angular.equals函数没有注意到顶层以下的变化。

有没有办法注入自定义相等比较器?

有没有办法动态更改watchExpression?因此,将监视应用于层次结构中的每个对象,并在层次结构更改时更改watchExpression

2 个答案:

答案 0 :(得分:1)

问题是import pandas as pd, numpy as np # Set up the test data df = pd.DataFrame(np.ceil(np.random.rand(1,10)*1000)) values = ["Value_"+str(i) for i in range(5)] colors = ["Color_"+str(i) for i in range(5)] df.columns = values + colors # Order idx = np.argsort(df[df.columns[5:]].values)[0] # Reverse (descending order) ridx = idx[::-1] df[df.columns[5:][ridx]] 会忽略以angular.equals()符号开头的密钥,即在您的情况下,$$type会在比较期间被忽略。

除Angulars自己的服务/指令/等外,不要在Angular代码中使用以$标志开头的属性!

Check out this fiddle并尝试将$values数组重命名为$values

答案 1 :(得分:1)

除了@ michael-rose的答案之外,我还添加了一项服务,用于转换webapi收到的数据:

var DataClenseService = function () {
"use strict";
this.renameFields = function (data, fieldRenames) {
    if (data == null) {
        return null;
    }

    if (typeof data !== 'object') {
        return data;
    }
    var service = this;
    Object.keys(data).forEach(function (propertyName) {
        var matchingRenames = fieldRenames.filter(function (rename) { return rename.old === propertyName; });
        var currentValue = data[propertyName];
        if (matchingRenames.length == 1) {
            delete data[propertyName];
            data[matchingRenames[0].new] = service.renameFields(currentValue, fieldRenames);
        } else {
            data[propertyName] = service.renameFields(currentValue, fieldRenames);
        }
    });
    return data;
};

};

并简单地将其称为:

var cleanedData = DataClenseService.renameFields(data, [{ old: '$values', new: 'values' }, { old: '$type', new: 'type' }]);