Можно расширить функциональность журнала Angular JS 1.2.18 $?
Я хотел бы выложить сообщение toastr для отображения сообщений журнала $. То есть:
$log.info('test'));
Похоже, что в AngularJS 1.2.19 и выше, $ provide.decorator - отличный способ расширить функциональность $ log. Конечно, я использую 1.2.18. Есть ли способ сделать это в 1.2.18?
В идеале я хотел бы расширить существующую функциональность, а не полностью ее переопределять.
Я не хочу изменять исходный код Angular.
1 ответ
Механизм декоратора - это сокращение для создания провайдера, который получает предыдущее определение и возвращает его новую версию.
Поэтому вы можете имитировать эту функцию следующим образом:
module.provider('$log', function ($logProvider) {
// $logProvider here is the one previously defined, from 'ng'
// unless someone else is overriding too.
this.$get = function ($injector) {
// Invoke the original provider.
var $log = $injector.invoke($logProvider.$get);
var oldInfo = $log.info;
// Override the method.
$log.info = function info() {
oldInfo.apply(this, arguments);
// (not actually useful to alert arguments; just an example)
alert(arguments);
}
return $log;
}
});
Конечно, это изменяет объект для всех иждивенцев, даже если они были вполне довольны стандартом $log
интерфейс, и означает, что у вас нет прямого способа увидеть в вашем приложении, какие сервисы зависят от стандартного интерфейса, а какие зависят от вашего расширенного интерфейса. Это может быть полезно, если вы хотите просто изменить поведение существующих методов с помощью переноса (например, для отправки журналов на ваш сервер или для отображения тостера, как вы упомянули в своем вопросе), но может быть рискованным выбором для добавления дополнительных методы, которые существующие абоненты не ожидают, где вы можете случайно нарушить совместимость со стандартным интерфейсом.
Вместо этого может быть лучше предоставить новую услугу, которую вы можете использовать в местах, где вы знаете, что вам нужно ваше расширение, и оставить встроенный $log
интерфейс в стандартной комплектации. Таким образом, будет легче заметить разницу и избежать непреднамеренных изменений в поведении стандартных вызывающих абонентов. Это похоже на вышеизложенное, но немного отличается в деталях:
module.provider('anotherLog', function ($logProvider) {
this.$get = function ($injector) {
var $log = $injector.invoke($logProvider.$get);
// Create a new object rather than extending the existing one in-place.
// This way the new method is only visible to callers that request
// 'anotherLog' instead of just '$log'.
var anotherLog = angular.extend(Object.create($log), {
sayHello: function sayHello() {
console.log('Hello!');
}
})
return anotherLog;
}
});
Оба этих подхода используют тот факт, что во время инициализации приложения используется отдельный "инжектор провайдера" для обработки зависимостей между провайдерами. Это отличается от основного $injector
который используется после создания приложения. Инъектор провайдера содержит всех провайдеров, которые были определены до сих пор, но не будет содержать результирующие сервисы, такие как $log
, Сама функция провайдера вводится с помощью инжектора провайдера, а ее $get
метод (как показано в этих примерах) вводится с основным $injector
,
Из-за этого различия, если вы зависите от каких-либо других служб для отображения вашего тостера, необходимо полагаться на них для $get
сам метод, а не провайдер в целом. Это позволит вам получить доступ к услугам в основном $injector
, а не только провайдеры из инжектора провайдера.