Трансляция не получена в директиве
У меня есть отношения родитель-потомок контроллера между моими <main>
, <div>
а также <my-directive>
в качестве таких:
<main ng-controller="MainController">
<nav>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</nav>
<div ng-controller="AboutController">
</div>
<my-directive></my-directive>
</main>
В MainController я выполняю трансляцию $ с:
$scope.$broadcast('shoppingCartReady', msg);
В AboutController я могу успешно получать эту трансляцию $ через:
angular.module('aboutModule', [])
.controller('AboutController', require('./about/aboutController'));
var AboutController = function ($scope, $rootScope) {
$scope.$on('shoppingCartReady', function(event, msg){
console.log(msg);
});
};
module.exports = [ '$scope', '$rootScope', AboutController];
Тем не менее, при попытке получить трансляцию $ внутри <my-directive>
Функция ссылки, кажется, никогда не будет получена:
angular.module('shopModule', [])
.directive('shopModuleDirective', require('./shopModuleDirective'))
.directive('myDirective', require('./myDirective'));
var myDirective = function ($rootScope) {
function link($scope, element, attrs, baseCtrl) {
$scope.$on('shoppingCartReady', function (event, msg) {
console.log(msg);
});
}
return {
restrict: 'E',
require: '^shopModuleDirective',
link: link
};
};
return ['$rootScope', myDirective];
ОБНОВИТЬ
Я даже создал контроллер в моей директиве:
angular.module('shopModule', [])
.directive('shopModuleDirective', require('./shopModuleDirective'))
.directive('myDirective', require('./myDirective'));
var myDirective = function ($rootScope) {
var controller = ["$scope", "$element", function ($scope, element) {
console.log('waiting for .on....');
$scope.$on('shoppingCartReady', function (event, cache) {
console.log('shoppingCartReady .on rcvd!');
});
}]
function link($scope, element, attrs, baseCtrl) {
$scope.$on('shoppingCartReady', function (event, msg) {
console.log(msg);
});
}
return {
restrict: 'E',
require: '^shopModuleDirective',
link: link
};
};
return ['$rootScope', myDirective];
Я вижу журнал для
console.log('waiting for .on....');
Но.on никогда не получен.
ОБНОВИТЬ:
Я думаю, что возможная причина в том, что сфера не "готова".
В моем оригинале broadcast
из MainController, если я выполню другой после setTime
из всех .on
получены:
MainController:
$scope.$broadcast('shoppingCartReady', msg);
setTimeout(function(){
$scope.$broadcast('shoppingCartReady', msg);
}, 8000);
2 ответа
Есть состояние гонки.
myDirective
контроллер и функция post-link выполняются после MainController
и слушатель настроен после shoppingCartReady
событие было запущено.
Основное правило для хорошей, проверяемой конструкции директивы - сохранять всю связанную с областью логику в контроллере, связывая функции и $onInit
hook используются именно для того, что должно происходить там, а не где-либо еще, например, для манипуляций с скомпилированным содержимым DOM.
Менее очевидный, но особый вариант использования link
является желаемым порядком выполнения (функции постсвязывания выполняются в обратном порядке, от дочерних к родительским). Если MainController
становится директивой, и scope.$broadcast('shoppingCartReady', msg)
выполнен в link
функция, а не контроллер, это гарантирует правильный порядок выполнения.
Оборачивание кода контроллера в ноль $timeout
также отложит код
$timeout(function(){
$scope.$broadcast('shoppingCartReady', msg);
});
будет выполняться после связывания функций в директивах child, но также будет обозначать некоторый запах кода. Это одна из причин, по которой события области видимости являются менее желательными способами директивной коммуникации и склонны быть анти-шаблонами.
Альтернативный способ справиться с этим зависит от того, что shoppingCartReady
Это событие, но в текущем случае оно избыточно: оно уже произошло в тот момент, когда выполняются дочерние контроллеры, они могут смело предполагать, что "корзина покупок готова".
Предлагаемое чтение для этой темы: Директивный контроллер и синхронизация ссылок в AngularJS.
Из документации:
$ broadcast (имя, аргументы);
Отправляет имя события вниз всем дочерним областям (и их дочерним элементам), уведомляя зарегистрированных слушателей $ rootScope.Scope.
Так как в вашей директиве вы не создаете новую область, я думаю, вы находитесь на том же уровне области, что и ваш MainController
, В этом случае вы не находитесь в childScope MainController
поэтому событие не может быть инициировано там. Я бы попробовал одно из следующего:
Трансляция ваших событий всегда через
$rootScope.$broadcast
, Все остальные области являются детьми$rootScope
и поэтому везде, где вы регистрируетесь на мероприятие с$scope.$on
, вы получите это. Вы также можете быть заинтересованы в том, почему мы используем трансляцию $rootScope.$ В AngularJS?Дайте вашу директиву изолированной
$scope
, Это будет действовать как childScope дляMainController
и должен работать так же. Выделение области действия директивы.В дополнение к опции
1.
Вы также можете использовать$rootScope.$emit
вместе с$rootScope.$on
, Для получения дополнительной информации читайте $rootScope.$ Broadcast против $ scope. $ Emit
Я всегда выбирала вариант 1.
как иногда вы не хотите, чтобы ваша директива имела изолированную область видимости.