Несомненно, ангуляр даёт вам силу. Но распределяться ей нужно с умом. Я постарался сформулировать три простых правила, которые я много раз нарушал и страдал от этого.
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 = []; } } ]);
И где-то во вьюшке вы отдаёте массив в какую-нибудь директиву, например, которая его отрисует.
<div my-array-viewer array="myArray"></div>
Что будет, если вызвать функцию 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.) в дочернем скоупе НЕ БУДЕТ затрагивать родительский скоуп, так как простые свойства при наследовании копируются. В отличие от них, объекты при прототипном наследовании передаются ссылками, поэтому изменение свойств объектов будет отображаться в родительском скоупе.
Поэтому так делать не следует, это не будет работать:
<div ng-if="true"> <a ng-click="showSecondBlock = true">Показать второй блок</a> </div> <div ng-if="showSecondBlock"> Второй блок отображается! </div>
Вместо этого, нужно иметь для таких дел специальный объект в $scope, назовём его viewModel
app.controller('MainCtrl', function($scope) { $scope.viewModel = {}; });
<div ng-if="true"> <a ng-click="viewModel.showSecondBlock = true">Показать второй блок</a> </div> <div ng-if="viewModel.showSecondBlock"> Второй блок отображается! </div>
ссылка на оригинал статьи http://habrahabr.ru/post/230761/
Добавить комментарий