У меня здесь несколько сложный сценарий, я попытаюсь изо всех сил объяснить это, извините, если это запутанно.
Скажем, у меня есть надуманный провайдер, который сидит в модуле, точно названном core
, назовите его actionProvider
, он может регистрировать действия, а затем вызывать их. И я использую его вот так:
// registering an action in m1 module
angular.module('m1').config((actionProvider)=> {
actionProvider.reg('myAction', { $fn: myActionFn });
myActionFn.$inject = ['$modal'];
function myActionFn($modal) {
$modal.open() // when action invoked it opens a modal dialog
}
})
// now somewhere else I invoke that previously registered action
angular.module('m2').controller('myCtrl', (action)=> {
action.invoke('myAction'); // and that calls $fn with $modal.open()
})
И это прекрасно работает. Теперь скажем, мне нужно проверить actionProvider
в модуле, который не имеет доступа к исходному коду actionProvider. Значит, мне нужно все это издеваться. ОК. Попробуем сделать это:
angular.module('core', []).provider('action', function() {
let self = this;
self.actions = [];
self.$get = ()=> { return self }; // essential function that every provider has
// registering action just pushes it into the array of actions,
// remember this is a fake provider
self.reg = (action)=> {
self.actions.push(action)
};
// yet even though it a fake it still needs to be able to invoke actions
self.invoke = (actionName) {
// so here I need to find specified action in the array and invoke it
};
})
Найти правильное действие в self.actions
легко. Но как правильно вызвать его $fn
? Как сообщить инжектору об обнаружении всех объектов, которые были введены (в случае myAction
это будет $modal
услуга)
Поиск того, что вводится в myActionFn
, легко, вам просто нужно проверить свойство функции $inject
.
Следующий шаг - просто вызвать функцию, передав ей то, что нужно ввести.
Использование Function.prototype.apply
в этом случае не поможет, так как нам нужно использовать угловую инъекцию. Создание экземпляра с angular.injector()
тоже не сработает, потому что нам нужно использовать правильный экземпляр инжектора.
Фокус в том, чтобы использовать angular.mock.injector
для захвата текущего инжектора.
поэтому наша функция invoke
должна выглядеть так:
self.invoke = (actionName) {
// instead of array it probably better to use an object map for 'actions'
let action = actions[actionName];
inject(($injector)=> {
$injector.invoke(action.$fn);
})
};