3

JavaScript でマルチレベル オブジェクト コレクションのメンバーを更新する最良の方法を教えてください。

これが私のコレクションの簡略版です。

this.Steps = [

{ id: 1, text: "test", childSteps: 
  [
    { id: 2, text: "test"},
    { id: 3, text: "test"},
    { id: 4, text: "test", childSteps: 
    [
           { id: 10, text: "test"},
           { id: 11, text: "test"}
    ]}
    },
    { id: 5, text: "test"},
    { id: 6, text: "test"},
    { id: 7, text: "test"},    
    { id: 8, text: "test"},
    { id: 9, text: "test"}
  ]
}
];

理想は、次のように呼び出される関数を持つことです。

updateObjectByID(11, 'string to be set');

オブジェクトが 1 レベルしかない場合、これは簡単に実行できます。しかし、マルチレベル コレクションで再帰を使用すると、はるかに難しくなります。

私は現在、コレクション全体を解析し、次のような文字列を構築する関数を使用しています:

this.Steps[0].childSteps[3].childSteps[1].text == "string to be set"

そして、eval()その文字列で行います。

もっときれいな解決策があるかもしれないと確信しています。

eval を使用すると、クラスを圧縮できなくなります。

どんな助けでも大歓迎です。

前もって感謝します

4

4 に答える 4

2

直接アクセスするために、ID でオブジェクトのマップを作成できます。

var map = {};
(function recurse(steps) {
    for (var i=0; i<steps.length; i++) {
        var step = steps[i];
        map[ step.id ] = step;
        if ("childSteps" in step)
            recurse(step.childSteps);
    }
})(this.Steps);

function updateObjectByID(id, string) {
    map[id].text = string;
}

あなたのコードについてのコメント: あなたは多くのことを過度に複雑にしました。条件if(obj.id == objId)が満たされたとき、あなたはobjすでにあなたの参照を持っています!!! これで、そのパスへのパスを検索し、そこから文字列を作成し、評価する必要がまったくなくなりました。そのプロパティに直接割り当てるだけです!

function(steps, objId, value, whatParam, command) {
    if (typeof whatParam == 'undefined')
        whatParam = 'selected';
    $.each(steps, function(index, obj){
        if(obj.id == objId) {
            // removed a lot of unecessary stuff

            // not sure, looks like "value" was evaled sometimes as well
            obj[whatParam] = value;

         } // insert an "else" here if ids are unique
         if (typeof obj.childSteps != 'undefined') {           
             this.setupObjectState(obj.childSteps, objId, value, whatParam, command);
         }
    });
}
于 2013-02-07T16:41:46.500 に答える
0

ID で呼び出すためupdateObjectById()、ID は一意である必要があります。次のように構造を変更してみませんか。

this.Steps = [
    { id: 1, text: "test" },
    { id: 2, parent: 1, text: "test" },
    { id: 3, parent: 1, text: "test" },
    { id: 4, parent: 1, text: "test" },
    { id: 10, parent: 4, text: "test" },
    { id: 11, parent: 4, text: "test" },
    { id: 5, parent: 1, text: "test"},
    { id: 6, parent: 1, text: "test"},
    { id: 7, parent: 1, text: "test"},    
    { id: 8, parent: 1, text: "test"},
    { id: 9, parent: 1, text: "test"}
]

このようにして、次のようにエントリを簡単に更新できます。

function updateObjectByID(id, text) {
    for(var i = 0; i < this.Steps.length; i++) {
        if(this.Steps[i].id === id) {
            this.Steps[i].text = text;
            break;
        }
    }
}

extra 属性parentを使用すると、次のように要素のすべての子を簡単に取得できます。

function getChildrenByID(id) {
    var array = [];
    for(var i = 0; i < this.Steps.length; i++) {
        if(this.Steps[i].parent === id) {
            array.push(this.Steps[i]);
        }
    }
    return array;
}
于 2013-02-07T16:43:08.973 に答える
0

ツリー構造を再帰的に降りて、ターゲット「id」を持つオブジェクトを検索し、そのテキストを置き換える必要があります。例えば:

function updateObjectByID(obj, id, text) {
  if (!obj) return;
  if (obj.id === id) {
    obj.text = text;
  } else if ((typeof(obj)==='object') && (obj.constructor===Array)) {
    for (var i=0; i<obj.length; i++) {
      updateObjectByID(obj[i], id, text);
    }
  } else if (obj.childSteps) {
    updateObjectByID(obj.childSteps, id, text);
  }
}

updateObjectByID(this.Steps, 11, 'String to be set');

ただし、このソリューションは、ツリーの剪定によって最適化できます。

于 2013-02-07T16:43:35.257 に答える
0
function updateObjectByID(id, text) {
    (function setText(steps) {
        for(var i = 0; i < steps.length; i++){
            var step = steps[i];
            if(step.id === id){
                step.text = text;
            }
            if ("childSteps" in step){
                setText(step.childSteps);
            }
        }
    })(this.Steps);
}

ここにデモがあります。http://jsfiddle.net/qDWX8/

于 2013-02-07T16:54:56.283 に答える