J'ai un tableau de deux objets:
genericItems: Item[] = [];
backupData: Item[] = [];
Je remplis ma table html avec genericItems
data. 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?
Essaye ça :
Cloner un tableau:
const myClonedArray = Object.assign([], myArray);
Cloner un objet:
const myClonedObject = Object.assign({}, myObject);
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);
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
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.
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
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
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:
Ai-je raison de penser que vous ne voulez pas que le troisième point se produise dans cet ordre?
Serait-ce mieux:
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;
});
}
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());
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
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));