web-dev-qa-db-fra.com

Pourquoi et quand utiliser angular.copy? (Copie profonde)

J'ai enregistré toutes les données reçues des services directement dans une variable, un contrôleur ou une étendue locale. Ce que je suppose serait considéré comme une copie superficielle, est-ce exact?

Example:

DataService.callFunction()
.then(function(response) {
  $scope.example = response.data;
});

Récemment, on m'a dit d'utiliser angular.copy afin de créer une copie en profondeur.

$scope.example = angular.copy(response.data);

Toutefois, les informations de copie profonde semblent fonctionner de la même manière lorsqu'elles sont utilisées par mon application Angular. Y at-il des avantages spécifiques à utiliser une copie en profondeur (angular.copy) et pouvez-vous s'il vous plaît me les expliquer?

127
Superman2971

Utilisez angular.copy lorsque vous attribuez une valeur d'objet ou de tableau à une autre variable et que la valeur object ne doit pas être modifiée.

Sans copie en profondeur ou en utilisant angular.copy , modification de la valeur de la propriété ou l'ajout de toute nouvelle propriété met à jour tous les objets référençant ce même objet.

var app = angular.module('copyExample', []);
app.controller('ExampleController', ['$scope',
  function($scope) {
    $scope.printToConsole = function() {
      $scope.main = {
        first: 'first',
        second: 'second'
      };

      $scope.child = angular.copy($scope.main);
      console.log('Main object :');
      console.log($scope.main);
      console.log('Child object with angular.copy :');
      console.log($scope.child);

      $scope.child.first = 'last';
      console.log('New Child object :')
      console.log($scope.child);
      console.log('Main object after child change and using angular.copy :');
      console.log($scope.main);
      console.log('Assing main object without copy and updating child');

      $scope.child = $scope.main;
      $scope.child.first = 'last';
      console.log('Main object after update:');
      console.log($scope.main);
      console.log('Child object after update:');
      console.log($scope.child);
    }
  }
]);

// Basic object assigning example

var main = {
  first: 'first',
  second: 'second'
};
var one = main; // same as main
var two = main; // same as main

console.log('main :' + JSON.stringify(main)); // All object are same
console.log('one :' + JSON.stringify(one)); // All object are same
console.log('two :' + JSON.stringify(two)); // All object are same

two = {
  three: 'three'
}; // two changed but one and main remains same
console.log('main :' + JSON.stringify(main)); // one and main are same
console.log('one :' + JSON.stringify(one)); // one and main are same
console.log('two :' + JSON.stringify(two)); // two is changed

two = main; // same as main

two.first = 'last'; // change value of object's property so changed value of all object property 

console.log('main :' + JSON.stringify(main)); // All object are same with new value
console.log('one :' + JSON.stringify(one)); // All object are same with new value
console.log('two :' + JSON.stringify(two)); // All object are same with new value
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="copyExample" ng-controller="ExampleController">
  <button ng-click='printToConsole()'>Explain</button>
</div>
159
Sarjan Desai

Dans ce cas, vous n'avez pas besoin d'utiliser angular.copy()

Explication:

  • = représente une référence alors que angular.copy() crée un nouvel objet sous forme de copie détaillée.

  • Utiliser = signifierait que modifier une propriété de response.data modifierait la propriété correspondante de $scope.example ou inversement.

  • En utilisant angular.copy(), les deux objets resteraient séparés et les modifications ne se refléteraient pas.

42
Nicolas2bert

Je dirais que angular.copy(source); n'est pas nécessaire dans votre situation si vous ne l'utilisez pas ultérieurement sans destination angular.copy(source, [destination]);.

Si une destination est fournie, tous ses éléments (pour les tableaux) ou ses propriétés (pour les objets) sont supprimés, puis tous les éléments/propriétés de la source y sont copiés.

https://docs.angularjs.org/api/ng/function/angular.copy

7
Esko

Je ne fais que partager mon expérience ici, j'ai utilisé angular.copy () pour comparer les propriétés de deux objets. Je travaillais sur un certain nombre d'entrées sans élément de formulaire, je me demandais comment comparer les propriétés de deux objets et, en fonction du résultat, je devais activer et désactiver le bouton de sauvegarde. Donc j'ai utilisé comme ci-dessous.

J'ai attribué une valeur utilisateur d'objet serveur d'origine à mon objet factice, par exemple userCopy, et utilisé watch pour vérifier les modifications apportées à l'objet utilisateur.

mon API de serveur qui me donne les données du serveur

var req = {
                method: 'GET',
                url: 'user/profile/'+id,
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }
            $http(req).success(function(data) {
                    $scope.user = data;
                    $scope.userCopy = angular.copy($scope.user);
                    $scope.btnSts=true;
            }).error(function(data) {
                $ionicLoading.hide();
            });

// initialement mon bouton de sauvegarde est désactivé parce que les objets sont identiques, une fois que quelque chose // change j'active Activation de la sauvegarde

$scope.btnSts=true;
$scope.$watch('user', function(newVal, oldVal){
    console.log($scope.userCopy.name);
    console.log();
    if ($scope.userCopy.name !== $scope.user.name || $scope.userCopy.email !== $scope.user.email ) {
        console.log('changed');
        $scope.btnSts=false;
    }else{
        console.log('unchanged');
        $scope.btnSts=true;
    }

}, true);

Je ne suis pas sûr mais la comparaison de deux objets était une véritable casse-tête pour moi toujours, mais avec angular.copy (), ça se passait bien.

1
Sudarshan Kalebere

Lors de l'utilisation de angular.copy, au lieu de mettre à jour la référence, un nouvel objet est créé et attribué à la destination (si une destination est fournie). Mais il y a plus. Il y a ce truc cool qui se passe après une copie en profondeur.

Supposons que vous ayez un service d'usine qui dispose de méthodes pour mettre à jour les variables d'usine.

angular.module('test').factory('TestService', [function () {
    var o = {
        shallow: [0,1], // initial value(for demonstration)
        deep: [0,2] // initial value(for demonstration)
    }; 
    o.shallowCopy = function () {
        o.shallow = [1,2,3]
    }
    o.deepCopy = function () {
        angular.copy([4,5,6], o.deep);
    }
    return o;
}]);

et un contrôleur qui utilise ce service,

angular.module('test').controller('Ctrl', ['TestService', function (TestService) {
     var shallow = TestService.shallow;
     var deep = TestService.deep;

     console.log('****Printing initial values');
     console.log(shallow);
     console.log(deep);

     TestService.shallowCopy();
     TestService.deepCopy();

     console.log('****Printing values after service method execution');
     console.log(shallow);
     console.log(deep);

     console.log('****Printing service variables directly');
     console.log(TestService.shallow);
     console.log(TestService.deep);
}]);

Lorsque le programme ci-dessus est exécuté, le résultat sera le suivant:

****Printing initial values
[0,1]
[0,2]

****Printing values after service method execution
[0,1]
[4,5,6]

****Printing service variables directly
[1,2,3]
[4,5,6]

La chose intéressante à propos de l'utilisation de angular copy est que les références de la destination sont reflétées avec le changement de valeur, sans avoir à réaffecter les valeurs manuellement.

1
Pubudu Dodangoda

Je sais que c'est déjà répondu, j'essaie toujours de le rendre simple. Donc angular.copy (data), vous pouvez utiliser dans le cas où vous souhaitez modifier/changer votre objet reçu en gardant ses valeurs d'origine non modifiées/inchangées.

Par exemple: supposons que j'ai fait appel api et obtenu mon originalObj, maintenant je veux changer les valeurs de api originalObj pour certains cas, mais je veux les valeurs d'origine aussi, donc ce que je peux faire est, je peux faire une copie de mon api originalObj dans duplicateObj et modifier duplicateObj de cette façon, mes valeurs originalObj ne changeront pas. En termes simples, la modification duplicateObj ne sera pas reflétée dans originalObj, contrairement à la façon dont js obj se comporte.

 $scope.originalObj={
            fname:'sudarshan',
            country:'India'
        }
        $scope.duplicateObj=angular.copy($scope.originalObj);
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

        $scope.duplicateObj.fname='SUD';
        $scope.duplicateObj.country='USA';
        console.log('---------After update-------')
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

Le résultat est comme ....

    ----------originalObj--------------
manageProfileController.js:1183 {fname: "sudarshan", country: "India"}
manageProfileController.js:1184 -----------duplicateObj---------------
manageProfileController.js:1185 {fname: "sudarshan", country: "India"}
manageProfileController.js:1189 ---------After update-------
manageProfileController.js:1190 ----------originalObj--------------
manageProfileController.js:1191 {fname: "sudarshan", country: "India"}
manageProfileController.js:1192 -----------duplicateObj---------------
manageProfileController.js:1193 {fname: "SUD", country: "USA"}
1
Sudarshan Kalebere