Улучшить эту документациюДекораторы в AngularJS
ПРИМЕЧАНИЕ: Это руководство предназначено для разработчиков, уже знакомых с основами AngularJS. Если вы только начинаете, рекомендуем начать с туториала.Что такое декораторы?
Декораторы — это паттерн проектирования, используемый для изменения класса (декорирования) без модификации исходного кода. В AngularJS декораторы — это функции, которые позволяют изменять сервис, директиву или фильтр перед их использованием.
Как использовать декораторы
Существует два способа регистрации декораторов
-
$provide.decorator, и module.decorator
Каждый предоставляет доступ к $delegate, который является экземпляром сервиса/директивы/фильтра, перед передачей в требующий его сервис.
$provide.decorator
Функция decorator предоставляет доступ к $delegate сервиса после его создания. Например:
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('$log', [
'$delegate',
function $logDecorator($delegate) {
var originalWarn = $delegate.warn;
$delegate.warn = function decoratedWarn(msg) {
msg = 'Decorated Warn: ' + msg;
originalWarn.apply($delegate, arguments);
};
return $delegate;
}
]);
}]);
После создания сервиса $log декоратор срабатывает. Функция декоратора получает объект $delegate, который предоставляет доступ к сервису, соответствующему селектору в декораторе. Этот $delegate будет сервисом, который вы декорируете. Возвращаемое значение функции переданной декоратору заменит декорируемый сервис, директиву или фильтр.
Данный $delegate может быть изменён или полностью заменён. При наличии сервиса myService с методом someFn, следующие решения могут быть приемлемыми:
Полная замена $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var myDecoratedService = {
// new service object to replace myService
};
return myDecoratedService;
}
]);
}]);
Модификация $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var someFn = $delegate.someFn;
function aNewFn() {
// new service function
someFn.apply($delegate, arguments);
}
$delegate.someFn = aNewFn;
return $delegate;
}
]);
}]);
Расширение $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
function helperFn() {
// an additional fn to add to the service
}
$delegate.aHelpfulAddition = helperFn;
return $delegate;
}
]);
}]);
Декораторы имеют различные правила для разных сервисов. Это связано с различными способами регистрации сервисов. Сервисы выбираются по имени, однако фильтры и директивы выбираются путём добавления "Filter" или "Directive" в конец имени. Предоставляемый $delegate диктуется типом сервиса.
| Тип сервиса | Селектор | $delegate |
|---|---|---|
| Сервис | serviceName | Значение object или function возвращаемое сервисом |
| Директива | directiveName + 'Directive' | Объект Array.<DirectiveObject>1
|
| Фильтр | filterName + 'Filter' | Значение function возвращаемое фильтром |
1. Несколько директивы могут быть зарегистрированы для одного селектора/имени
$delegate сервиса. Необходимо не только соблюдать ожидания потребителя, но и учитывать, что некоторые функции (такие как регистрация директивы) не выполняются после декорации, а во время создания/регистрации исходного сервиса. Это означает, например, что действие по добавлению объекта директивы в массив директивы $delegate вероятно приведёт к непредсказуемому поведению. Кроме того, следует проявлять особую осторожность при декорировании основных сервисов, директивы или фильтров, так как это может неожиданно или отрицательно повлиять на функциональность фреймворка. module.decorator
Эта функция аналогична функции $provide.decorator, но доступна через API модуля. Это позволяет отделить шаблоны декораторов от блоков конфигурации модуля.
Как и с $provide.decorator, функция module.decorator выполняется на стадии конфигурации приложения. Это означает, что вы можете определить module.decorator до определения декорируемого сервиса.
Поскольку вы можете применять несколько декораторов, следует учитывать, что применение декораторов всегда происходит в порядке объявления:
- Если сервис декорирован и функцией
$provide.decoratorиmodule.decorator, декораторы применяются в порядке:
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.config(function($provide) {
$provide.decorator('theFactory', provideDecoratorFn); // runs first
})
.decorator('theFactory', moduleDecoratorFn); // runs seconds
- Если сервис объявлен несколько раз, декоратор будет применён к последнему объявлению сервиса:
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.decorator('theFactory', moduleDecoratorFn)
.factory('theFactory', theOtherFactoryFn);
// `theOtherFactoryFn` is selected as 'theFactory' provider and it is decorated via `moduleDecoratorFn`.
Примеры применения
В следующих разделах приведены примеры декоратора сервиса, декоратора директивы и декоратора фильтра.
В этом примере показано, как можно заменить сервис $log своим собственным для отображения сообщений об ошибках.
Пропущенные интерполированные выражения в атрибутах ng-href могут легко остаться незамеченными. Мы можем декорировать ngHref для оповещения о таких условиях.
Предположим, вы создали приложение, использующее стандартный формат для многих фильтров Date. Внезапно изменились требования, и теперь все наши даты по умолчанию должны быть в формате 'shortDate' вместо 'mediumDate'.
© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.6.9/docs/guide/decorators