AngularJS
AngularJS gotchas и ловушки
Поиск…
Двухсторонняя привязка данных перестает работать
Следует иметь в виду, что:
- Угловое связывание данных основывается на прототипном наследовании JavaScript, поэтому оно подвержено переменному затенению .
- Дочерняя область, обычно прототипически наследуемая от своей родительской области. Единственное исключение из этого правила - это директива, которая имеет изолированную область действия, поскольку она не прототипически наследуется.
- Существуют некоторые директивы, которые создают новую дочернюю область:
ng-repeat
,ng-switch
,ng-view
,ng-if
,ng-controller
,ng-include
и т. Д.
Это означает, что когда вы пытаетесь выполнить двустороннюю привязку некоторых данных к примитиву, находящемуся внутри детской области (или наоборот), все может работать не так, как ожидалось. Вот пример того, как легко «сломать» AngularJS.
Эту проблему можно легко избежать, выполнив следующие шаги:
- Имейте "." внутри вашего HTML-шаблона всякий раз, когда вы связываете некоторые данные
- Используйте синтаксис
controllerAs
поскольку он способствует использованию привязки к «пунктируемому» объекту - $ parent может использоваться для доступа к переменным родительской
scope
а не к области содержимого. как внутриng-if
мы можем использоватьng-model="$parent.foo"
..
Альтернативой для этого является привязка ngModel
к функции getter / setter, которая будет обновлять кэшированную версию модели при вызове с аргументами или возвращать ее при вызове без аргументов. Чтобы использовать функцию getter / setter, вам нужно добавить ng-model-options="{ getterSetter: true }"
к элементу с атрибутом ngModal
и вызвать функцию getter, если вы хотите отобразить ее значение в выражении ( Рабочий пример ).
пример
Посмотреть:
<div ng-app="myApp" ng-controller="MainCtrl">
<input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
<div ng-if="truthyValue">
<!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo() }}</div>
</div>
контроллер:
angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
$scope.truthyValue = true;
var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model
$scope.foo = function(val) {
// the function return the the internal '_foo' varibale when called with zero arguments,
// and update the internal `_foo` when called with an argument
return arguments.length ? (_foo = val) : _foo;
};
}]);
Лучшая практика . Лучше всего держать геттеры быстрыми, потому что Угловые, скорее всего, назовут их чаще, чем другие части вашего кода ( ссылка ).
Что делать при использовании html5Mode
При использовании html5Mode([mode])
необходимо:
Вы указываете базовый URL-адрес приложения с
<base href="">
вindex.html
вашегоindex.html
.Важно, чтобы
base
тег появился перед любыми тегами с запросами url. В противном случае это может привести к этой ошибке -"Resource interpreted as stylesheet but transferred with MIME type text/html"
. Например:<head> <meta charset="utf-8"> <title>Job Seeker</title> <base href="/"> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="/styles/main.css"> </head>
Если вы не хотите указывать
base
тег, настройте$locationProvider
чтобы не требоватьbase
тег, передав объект определения сrequireBase:false
в$locationProvider.html5Mode()
следующим образом:$locationProvider.html5Mode({ enabled: true, requireBase: false });
Чтобы поддерживать прямую загрузку URL-адресов HTML5, вам необходимо активировать переписывание URL-адресов на стороне сервера. From AngularJS / Руководство разработчика / Использование $ location
Использование этого режима требует перезаписи URL-адресов на стороне сервера, в основном вы должны переписать все свои ссылки на точку входа вашего приложения (например,
index.html
). Требование<base>
также важно для этого случая, так как позволяет Angular различать часть URL-адреса, которая является базой приложения, и путь, который должен обрабатывать приложение.Отличный ресурс для запросов перезаписи запросов для различных реализаций HTTP-сервера можно найти в FAQ по ui-router - Как настроить сервер для работы с html5Mode . Например, сходница
RewriteEngine on # Don't rewrite files or directories RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # Rewrite everything else to index.html to allow html5 state links RewriteRule ^ index.html [L]
Nginx
server { server_name my-app; root /path/to/app; location / { try_files $uri $uri/ /index.html; } }
экспресс
var express = require('express'); var app = express(); app.use('/js', express.static(__dirname + '/js')); app.use('/dist', express.static(__dirname + '/../dist')); app.use('/css', express.static(__dirname + '/css')); app.use('/partials', express.static(__dirname + '/partials')); app.all('/*', function(req, res, next) { // Just send the index.html for other files to support HTML5Mode res.sendFile('index.html', { root: __dirname }); }); app.listen(3006); //the port you want to use
7 Смертельные грехи AngularJS
Ниже приведен список ошибок, которые разработчики часто делают во время использования функций AngularJS, некоторые извлеченные уроки и решения для них.
1. Манипуляция DOM через контроллер
Это законно, но его следует избегать. Контроллеры - это места, где вы определяете свои зависимости, связываете свои данные с представлением и делаете дальнейшую бизнес-логику. Вы можете технически манипулировать DOM в контроллере, но всякий раз, когда вам нужна такая же или аналогичная манипуляция в другой части вашего приложения, вам понадобится другой контроллер. Поэтому лучшей практикой такого подхода является создание директивы, включающей все манипуляции и использование директивы во всем приложении. Следовательно, контроллер оставляет представление неповрежденным и делает его работу. В директиве функция связывания - лучшее место для манипулирования DOM. Он имеет полный доступ к области и элементу, поэтому, используя директиву, вы также можете воспользоваться преимуществами повторного использования.
link: function($scope, element, attrs) {
//The best place to manipulate DOM
}
Вы можете получить доступ к элементам DOM при связывании функции несколькими способами, такими как параметр element
, angular.element()
или чистый Javascript.
2. Связывание данных при переходе
AngularJS славится своей двусторонней привязкой данных. Однако иногда вы можете столкнуться с тем, что ваши данные только односторонне связаны внутри директив. Остановитесь там, AngularJS не ошибается, но, вероятно, вы. Директивы - это немного опасные места, так как задействованы дочерние области и изолированные области. Предположим, что у вас есть следующая директива с одним заключением
<my-dir>
<my-transclusion>
</my-transclusion>
</my-dir>
И внутри моего переключения у вас есть некоторые элементы, привязанные к данным во внешней области.
<my-dir>
<my-transclusion>
<input ng-model="name">
</my-transclusion>
</my-dir>
Вышеприведенный код не будет работать правильно. Здесь переключение создает дочернюю область, и вы можете получить переменную имени, но все изменения, внесенные вами в эту переменную, останутся там. Таким образом, вы можете действительно использовать эту переменную как $ parent.name . Однако это использование может быть не лучшей практикой. Лучшим подходом было бы обертывание переменных внутри объекта. Например, в контроллере вы можете создать:
$scope.data = {
name: 'someName'
}
Затем в выводе вы можете получить доступ к этой переменной через объект «data» и увидеть, что двусторонняя привязка работает отлично!
<input ng-model="data.name">
Не только в переходах, но и во всем приложении, рекомендуется использовать пунктирную нотацию.
3. Несколько директив вместе
Фактически законно использовать две директивы вместе внутри одного и того же элемента, если вы подчиняетесь правилу: две изолированные области не могут существовать на одном элементе. Вообще говоря, при создании новой настраиваемой директивы вы выделяете изолированную область для простой передачи параметров. Предполагая, что в директивах myDirA и myDirB есть выделенные области и myDirC нет, следующий элемент будет действителен:
<input my-dir-a my-dirc>
тогда как следующий элемент вызовет ошибку консоли:
<input my-dir-a my-dir-b>
Поэтому директивы должны использоваться разумно, принимая во внимание области.
4. Неправильное использование $ emit
$ emit, $ broadcast и $ on, они работают в принципе отправителя-получателя. Другими словами, они являются средством связи между контроллерами. Например, следующая строка испускает «someEvent» из контроллера A, который должен быть захвачен соответствующим контроллером B.
$scope.$emit('someEvent', args);
И следующая строка ловит 'someEvent'
$scope.$on('someEvent', function(){});
Пока все кажется идеальным. Но помните, что если контроллер B еще не вызывается, событие не будет выловлено, что означает, что для его работы должны быть задействованы как контроллеры-эмиттеры, так и приемники. Итак, опять же, если вы не уверены, что вам определенно нужно использовать $ emit, создание службы кажется лучшим способом.
5. Неправильное использование $ scope. $ Watch
$ scope. $ watch используется для просмотра изменения переменной. Всякий раз, когда переменная изменена, этот метод вызывается. Однако одна распространенная ошибка заключается в изменении переменной внутри $ scope. $ Watch. Это вызовет непоследовательность и бесконечный цикл $ digest в какой-то момент.
$scope.$watch('myCtrl.myVariable', function(newVal) {
this.myVariable++;
});
Поэтому в приведенной выше функции убедитесь, что у вас нет операций с myVariable и newVal.
6. Методы привязки к представлениям
Это один из самых тяжких грехов. У AngularJS есть двусторонняя привязка, и всякий раз, когда что-то меняется, представления обновляются много раз. Таким образом, если вы привязываете метод к атрибуту представления, этот метод потенциально может называться сто раз, что также приводит вас в замешательство во время отладки. Однако для привязки метода существуют только некоторые атрибуты, такие как ng-click, ng-blur, ng-on-change и т. Д., Которые ожидают, что методы будут использоваться как пареметр. Например, предположим, что в вашей разметке есть следующее представление:
<input ng-disabled="myCtrl.isDisabled()" ng-model="myCtrl.name">
Здесь вы проверяете отключенное состояние представления с помощью метода isDisabled. В контроллере myCtrl у вас есть:
vm.isDisabled = function(){
if(someCondition)
return true;
else
return false;
}
Теоретически это может показаться правильным, но технически это вызовет перегрузку, поскольку метод будет работать бесчисленное количество раз. Чтобы решить эту проблему, вы должны привязать переменную. В вашем контроллере должна существовать следующая переменная:
vm.isDisabled
Вы можете снова инициировать эту переменную при активации контроллера
if(someCondition)
vm.isDisabled = true
else
vm.isDisabled = false
Если условие нестабильно, вы можете связать это с другим событием. Затем вы должны привязать эту переменную к виду:
<input ng-disabled="myCtrl.isDisabled" ng-model="myCtrl.name">
Теперь все атрибуты представления имеют то, что они ожидают, и методы будут выполняться только тогда, когда это необходимо.
7. Не использовать функции Углового
AngularJS обеспечивает большое удобство с некоторыми его функциями, не только упрощает ваш код, но и делает его более эффективным. Некоторые из этих функций перечислены ниже:
- angular.forEach для петель (осторожно, вы не можете «сломать», это может предотвратить только попадание в тело, поэтому рассмотрите производительность здесь.)
- угловой.элемент для DOM-селекторов
- angular.copy : используйте это, когда вы не должны изменять основной объект
- Валидации формы уже потрясающие. Используйте грязную, девственную, тронутую, действительную, необходимую и так далее.
- Помимо отладчика Chrome, используйте удаленную отладку для разработки мобильных устройств.
- И убедитесь, что вы используете Batarang . Это бесплатное расширение Chrome, где вы можете легко просматривать области ,