Несомненно, ангуляр даёт вам силу. Но пользоваться ей нужно с умом. Я постарался сформулировать три простых правила, которые я много раз нарушал и страдал от этого.
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>
Пишите в комментариях, о какие ещё особенности ангуляр-way вам довелось набить шишек.
Автор: Houston