С большой силой приходит и большая ответственность — техника безопасности в AngularJS
Несомненно, ангуляр даёт вам силу. Но пользоваться ей нужно с умом. Я постарался сформулировать три простых правила, которые я много раз нарушал и страдал от этого.
1. Делайте копию объекта, если он может подвергнуться нежелательным изменениям.В ангуляре данные по умолчанию едины, и если вы измените их намеренно, случайно или в результате ошибки, под угрозой окажутся все места его использования. Например, у нас есть фабрика пустых сущностей, которые будут использованы для заполнения форм. module.factory ('emptyEntity', function () { var emptyObject = { name:», surname:», address:{ city:» street:», } };
return { createEmptyEntity: function (){ return emptyObject; } };
}); И далее, в контроллере формы мы создаём в $scope этот пустой объект и используем его как модель формы. $scope.model = mapper.createEmptyPetition (); Что будет, если при вводе формы эта модель изменится, а потом вызвать mapper.createEmptyPetition () снова для другой формы? Так, как везде используется один и тот же экземпляр объекта emptyObject, изменения будут отражены в нём, и при следующем вызове mapper.createEmptyPetition () мы получим грязный и использованный объект. Подобных моментов при разработке может возникать великое множество, и нужно осторожно относиться к раздаче ссылок на объекты направо и налево. В данном случае следовало бы сделать вот так — возвращать копию объекта, чтобы её изменения не касались оригинального объекта: createEmptyEntity: function (){ return angular.copy (emptyObject); } 2. Не теряйте ссылку на объект/массив, если не хотите потерять синхронизацию данных Простой пример.У нас есть контроллер, в $scope которого лежит массив, и есть функция для очищения массива: module.controller («NewPetitionController», ['$scope', function ($scope) { $scope.myArray = [1,2,3,4];
$scope.cleanArray = function (){ $scope.myArray = []; } } ]); И где-то во вьюшке вы отдаёте массив в какую-нибудь директиву, например, которая его отрисует.
Что будет, если вызвать функцию cleanArray? Директива спокойно продолжит отображать старый добрый полный массив, потому что у неё осталась ссылка на него. А кодом »$scope.myArray = []» мы только создали новый массив и записали ссылку на него в свойство myArray, на что директиве my-array-viewer абсолютно параллельно. Чтобы занулить массив, не потеряв на него ссылку, нужно просто вызвать $scope.myArray.length = 0; То же касается объектов. Нельзя просто взять и присвоить переменной новый объект, нужно изменить старый, чтобы остальные части прилоежния, имеющие ссылку на этот объект, не потеряли её. module.controller («NewPetitionController», ['$scope', function ($scope) { $scope.myObj = {foo: «bar»};$scope.setObj = function (newObj){ //$scope.myObj = newObj; //Так делать нельзя, это приведёт к утере ссылки angular.extend ($scope.myObj, newObj); //нужно вот так, чтобы изменился исходный объект } } ]); 3. Будьте внимательны с дочерними $scope Многие директивы, такие как ng-if, ng-include создают дочерний $scope. Что это значит? У этих директив будет создан новый экземпляр $scope, в свойстве prototype которого будет родительский скоуп — стандартной javascript-наследование. Из этого следует, что изменение простых свойств (string, number, boolean etc.) в дочернем скоупе НЕ БУДЕТ затрагивать родительский скоуп, так как простые свойства при наследовании копируются. В отличие от них, объекты при прототипном наследовании передаются ссылками, поэтому изменение свойств объектов будет отображаться в родительском скоупе.Поэтому так делать не следует, это не будет работать: