2017-06-28 4 views
1

に配列のクローンを作成します。私は2つのオブジェクトの配列を持っている:はtypescriptです

genericItems: Item[] = []; 
backupData: Item[] = []; 

私はgenericItemsデータと私のHTMLテーブルを移入しています。テーブルは変更可能です。 backUpDataで行われたすべての変更を元に戻すためのリセットボタンがあります。この配列は、サービスによって取り込まれ:

getGenericItems(selected: Item) { 
this.itemService.getGenericItems(selected).subscribe(
    result => { 
    this.genericItems = result; 
    }); 
    this.backupData = this.genericItems.slice(); 
    } 

私の考えは、ユーザの変更が最初の配列に反映されますと二番目の配列は、リセット動作のためのバックアップとして使用することができる、ということでした。私がここで直面している問題は、ユーザーがテーブル(genericItems [])を変更して、2番目の配列backupDataも変更されたときです。これはどうやって起こり、これを防ぐには?

+0

アレイの浅いコピーを作成したようです。あなたが保持していたオブジェクトを変更して、変更を見ているように聞こえます。深いコピーを作成するか、データを表現するために別の方法を考え出す必要があります。 –

+0

同じ参照を指しています。 lodashなどのライブラリを使用して新しい配列を返すと、その問題は発生しません。 –

+0

'slice()'は別の配列から新しいオブジェクトを作成します。 – Arun

答えて

1

はこれを試してください:あなたは配列のコピーを行っているところへとミスを犯したかもしれないよう

[https://lodash.com/docs/4.17.4#clone][1] 

var objects = [{ 'a': 1 }, { 'b': 2 }]; 

var shallow = _.clone(objects); 
console.log(shallow[0] === objects[0]); 
// => true 
+0

'result => { this.genericItems = result; this.resetBackupData = _.clone(result); }); ' に動作していない...まだ – Arun

0

は、それは見えます。私の説明を見て、データを元の状態にリセットするのに役立つはずのコードを少し修正してください。

あなたの例では、私は、次の服用場所を見ることができます:

  • あなたは一般的な項目
  • を取得するための要求をしているあなたは、データを取得した後、あなたがthis.genericItems
  • に結果を設定しますあなたは

は、私は右のあなたは第三のポイントはで発生したくない考えでアム結果としてBACKUPDATAを設定し、直接その後

  • その順序?

    はこれが良いだろう:

    • あなたは、データ要求
    • を行うthis.genericItems
    • で、現在あるもののバックアップコピーは、その後、あなたの要求
    • の結果としてgenericItemsを設定してください

    これを試してみてください:

    getGenericItems(selected: Item) { 
        this.itemService.getGenericItems(selected).subscribe(
        result => { 
         // make a backup before you change the genericItems 
         this.backupData = this.genericItems.slice(); 
    
         // now update genericItems with the results from your request 
         this.genericItems = result; 
        }); 
        } 
    
  • +0

    ' this.backupData = this.genericItems.slice()変更されます; ' 一般的な項目、私が試したスライス()' ' ための空である: を' ... 結果=> { this.backupData = result; this.genericItems = result; }); が動作していない – Arun

    +0

    @ArunRaj genericItemsのバックアップをいつ作成しますか?その結果をthis.genericItemsに設定すると同時にコメントに投稿した内容がうまくいくはずです。結果にデータが表示されていますか?デバッガをクロムに置き、データの内容を見てください –

    0

    あなたのコード内の次の行は、新しい配列に新しい配列、コピーgenericItemsからすべてのオブジェクト参照を作成し、backupDataに割り当てます

    this.backupData = this.genericItems.slice(); 
    

    のでbackupDataながらgenericItemsは異なる配列です、彼らは同じ正確なオブジェクト参照を含みます。

    (@ LatinWarriorが言及したように)あなたのためにディープコピーを行うためにライブラリを持ってきても構いません。

    しかしItemがあまりにも複雑ではない場合は、多分あなたはオブジェクトに深いクローンにそれに自分をcloneメソッドを追加することができます。

    class Item { 
        somePrimitiveType: string; 
        someRefType: any = { someProperty: 0 }; 
    
        clone(): Item { 
        let clone = new Item(); 
    
        // Assignment will copy primitive types 
    
        clone.somePrimitiveType = this.somePrimitiveType; 
    
        // Explicitly deep copy the reference types 
    
        clone.someRefType = { 
         someProperty: this.someRefType.someProperty 
        }; 
    
        return clone; 
        } 
    } 
    

    次に、各項目にclone()を呼び出す:

    this.backupData = this.genericItems.map(item => item.clone()); 
    
    0

    ルックスあなたが望むようにディープコピーオブジェクトです。 Object.assign()を使用してみませんか?いいえするライブラリは必要ありませんし、そのワンライナー:)

    getGenericItems(selected: Item) { 
        this.itemService.getGenericItems(selected).subscribe(
         result => { 
          this.genericItems = result; 
          this.backupDate = Object.assign({}, result); 
          //this.backupdate WILL NOT share the same memory locations as this.genericItems 
          //modifying this.genericItems WILL NOT modify this.backupdate 
         }); 
    } 
    

    もっとObject.assign()上:コードの下https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

    +0

    私はこれに大きな期待をしていましたが、 'genericItems'を変更しても' backupData'も変更されました。私は何が起こっているのか分かりません。 – Arun

    +0

    これは 'slice()'と同じことを行います。新しい配列を作成しますが、古い配列からオブジェクト参照をコピーします。 –

    +0

    また、私はそれが 'Object.assign([]、result)'であるべきだと思います。さもなければ、私はあなたが 'length'プロパティ(と多分何か他のもの)を失うと思います。 –

    0

    が第1レベルは、以下のためにそう

    let original = [{ a: 1 }, {b:1}] 
    const copy = [ ...original ].map(item=>({...item})) 
    

    をオブジェクトにコピーするためにあなたを助けるかもしれません場合、値はそのまま残ります。

    copy[0].a = 23 
    console.log(original[0].a) //logs 1 -- value didn't change voila :) 
    

    、この場合のために

    let original = [{ a: {b:2} }, {b:1}] 
    const copy = [ ...original ].map(item=>({...item})) 
    copy[0].a.b = 23; 
    console.log(original[0].a) //logs 23 -- lost the original one :(
    

    を失敗最終的なアドバイス:

    私はあなたが完全に元の年代から逆参照オブジェクト内のオブジェクトをコピーするのに役立ちますlodash cloneDeep APIのために行くと言うでしょう。これは別のモジュールとしてインストールできます。私はprimeNgのDataTableと同じ問題を持っているhttps://www.npmjs.com/package/lodash.clonedeep

    1

    https://github.com/lodash/lodash

    個々のパッケージ

    は、ドキュメントを参照してください。試して泣いた後、このコードを使用して問題を修正しました。リセットするためのバックアップ値

    backupData = this.deepArrayCopy(genericItems); 
    

    を初期化するための

    private deepArrayCopy(arr: SelectItem[]): SelectItem[] { 
        const result: SelectItem[] = []; 
        if (!arr) { 
         return result; 
        } 
        const arrayLength = arr.length; 
        for (let i = 0; i <= arrayLength; i++) { 
         const item = arr[i]; 
         if (item) { 
         result.push({ label: item.label, value: item.value }); 
         } 
        } 
        return result; 
        } 
    

    は特効薬は{}を使用して代わりにコンストラクタを呼び出すことによって、アイテムを再作成することです

    genericItems = this.deepArrayCopy(backupData); 
    

    変更します。 new SelectItem(item.label, item.value)が動作しませんでした。

    6

    これを試してみてください:

    クローン配列を:

    const myClonedArray = Object.assign([], myArray); 
    

    クローンオブジェクトを:

    const myClonedObject = Object.assign({}, myObject); 
    
    0

    配列のクローンを作成する最も簡単な方法は、 BACKUPDATA = genericItemsです。 concat();

    これにより、アレイインデックスの新しいメモリが作成されます

    関連する問題