web-dev-qa-db-fra.com

Créer un clone d'un tableau en dactylographie

J'ai un tableau de deux objets:

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

Je remplis ma table html avec genericItemsdata. La table est modifiable. Il existe un bouton de réinitialisation pour annuler toutes les modifications effectuées avec backUpData. Ce tableau est rempli par un service:

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

Mon idée était que les modifications apportées aux utilisateurs seraient reflétées dans le premier tableau et que le second tableau pourrait être utilisé comme sauvegarde pour l'opération de réinitialisation. Le problème auquel je suis confronté est lorsque l'utilisateur modifie la table (genericItems []), le deuxième tableau backupData est également modifié. Comment cela se passe-t-il et comment empêcher cela?

22
Arun

Essaye ça :

Cloner un tableau:

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

Cloner un objet:

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

Dans TypeScript et ES6, vous pouvez utiliser l'opérateur spread:

const myClonedArray  = [...myArray];

L'opérateur de diffusion travaille également sur l'objet mais il ne fera qu'une copie superficielle (première couche d'enfants)

const myCloneObject = {..myObject};

Pour faire une copie complète d'un objet, vous avez besoin d'une bibliothèque externe:

 import * as cloneDeep from 'lodash/cloneDeep';
 const deeplyClonedObject = cloneDeep(myObject);
6
David Dehghan

le moyen le plus simple de cloner un tableau est backUpData = genericItems.concat ();

Cela va créer une nouvelle mémoire pour les index de tableau

1
VarunJi

J'ai le même problème avec primeNg DataTable. Après avoir essayé et pleuré, j'ai résolu le problème en utilisant ce code.

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;
  }

Pour initialiser la valeur de sauvegarde

backupData = this.deepArrayCopy(genericItems);

Pour réinitialiser les modifications 

genericItems = this.deepArrayCopy(backupData);

La solution miracle consiste à recréer des éléments en utilisant {} au lieu d'appeler le constructeur . J'ai déjà essayé new SelectItem(item.label, item.value) qui ne fonctionne pas.

1
mehdinf

Essaye ça:

[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
1
Latin Warrior

On dirait que ce que vous voulez, c'est Deep Copy de l'objet. Pourquoi ne pas utiliser Object.assign()? Aucune bibliothèque requise, et c'est un one-liner :)

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
        });
}

Plus sur Object.assign(): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

0
CozyAzure

Il semble que vous ayez commis une erreur quant à l'emplacement où vous effectuez la copie d'un tableau. Regardez mon explication ci-dessous et une légère modification du code qui devrait vous aider à rétablir les données à leur état précédent.

Dans votre exemple, je peux voir ce qui suit se dérouler:

  • vous faites une demande pour obtenir des articles génériques
  • après avoir obtenu les données, vous définissez les résultats avec les this.genericItems
  • directement après que vous définissez le backupData comme résultat

Ai-je raison de penser que vous ne voulez pas que le troisième point se produise dans cet ordre?

Serait-ce mieux:

  • vous faites la demande de données
  • faire une copie de sauvegarde de ce qui est courant dans this.genericItems
  • puis définissez genericItems comme résultat de votre demande

Essaye ça:

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
Molik Miah

La ligne suivante de votre code crée un nouveau tableau, copie toutes les références d'objet de genericItems dans ce nouveau tableau et l'assigne à backupData:

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

Ainsi, alors que backupData et genericItems sont des tableaux différents, ils contiennent les mêmes références d'objet exactes. 

Vous pouvez faire venir une bibliothèque pour effectuer une copie en profondeur pour vous (comme mentionné par @LatinWarrior). 

Mais si Item n'est pas trop complexe, vous pouvez peut-être y ajouter une méthode clone pour cloner en profondeur l'objet vous-même:

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;
  }
}

Ensuite, appelez clone() sur chaque élément:

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

Le code ci-dessous peut vous aider à copier les objets de premier niveau 

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

so pour les cas précédents, les valeurs restent intactes

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

Échec pour ce cas

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 :(

Dernier conseil:

Je dirais que go for lodash cloneDeep API, qui vous aide à copier les objets à l’intérieur des objets en déviant complètement des objets originaux. Ceci peut être installé en tant que module séparé.

Voir la documentation:https://github.com/lodash/lodash

Paquet individuel: https://www.npmjs.com/package/lodash.clonedeep

0
Nirus

L'utilisation de map ou d'une autre solution similaire n'aide pas à cloner en profondeur un tableau d'objets. Un moyen plus simple de procéder sans ajouter de nouvelle bibliothèque consiste à utiliser JSON.stringfy, puis JSON.parse.

Dans votre cas, cela devrait marcher:

this.backupData = JSON.parse(JSON.stringify( genericItems));
0
jmuhire