Связь с Angularjs между директивами с публикацией/подпиской
Я хочу создать механизм публикации/подписки с системой событий angular.
angular.module("app",[]);
angular.module("app").directive("first", function($rootScope){
return {
template: "First Directive",
link:function(scope,element,attribute){
$rootScope.$broadcast("OnFirstDirectiveCreated", {
"message": "I'm first directive"
});
}
}
})
angular.module("app").directive("second", function($rootScope){
return {
template: "Second Directive",
link:function(scope,element,attribute){
var handler = $rootScope.$on("OnFirstDirectiveCreated",
function (event, args) {
console.log("First Directive Message: " + args.message);
});
}
}
})
если я устанавливаю HTML-документ таким образом, в консоли не появляется сообщение:
<div ng-app="app">
<first></first>
<second></second>
</div>
Если я меняю порядок первым и вторым, на сервере будет отображаться сообщение wirite.
<div ng-app="app">
<second></second>
<first></first>
</div>
Но мне нужна первая директива или внутренняя директива.
<div ng-app="app">
<first></first>
<second></second>
</div>
<div ng-app="app">
<first>
<second></second>
</first>
</div>
Я пробовал как $rootScope.$broadcast
, так и $rootScope.$emit
, но не смотрел.
Рабочий DEMO
Ответы
Ответ 1
Это абсолютно правильное поведение angular.
В первом примере:
<first></first>
<second></second>
Angular создает директиву для тега first
и отправляет событие немедленно, но вторая директива еще не создана.
Во втором примере:
<first></first>
<second></second>
Здесь вы сначала подписываетесь на событие, а после этого директива first
отправляет сообщение. Из-за этого директива second
принимает событие.
Третий пример:
<first>
<second></second>
</first>
Этот случай, как и первый пример, не будет работать.
Решение:
Одним из решений является установка тайм-аута в первой директиве, чтобы не отправлять событие сразу после создания. Если второй параметр $timeout
, delay
не указан, поведение по умолчанию заключается в выполнении функции после завершения рендеринга DOM:
angular.module("app").directive("first", function($rootScope, $timeout) {
return {
template: "First Directive",
link: function(scope,element,attribute) {
$timeout(function() {
$rootScope.$broadcast("OnFirstDirectiveCreated", {
"message": "I'm first directive"
})
});
}
}
});
Демо
Ответ 2
Это происходит потому, что, когда выполняется трансляция первой директивы, вторая директива не готова и, следовательно, сигнал теряется и связь не происходит. Один из способов его решения - многократно посылать сигнал с использованием функции $interval и прекращать передачу только тогда, когда вторая директива готова. Конечно, вторая директива должна транслировать назад, когда она получает данные от первого.
Второе решение, для которого я должен был пойти, заключается в том, что вторая директива уведомляет, когда она готова к первой директиве, транслируя с помощью $rootScope так же, как в первой директиве.
angular.module("app").directive("second", function($rootScope){
return {
template: "Second Directive",
link:function(scope,element,attribute){
var handler = $rootScope.$on("secondDirective",
function (event, args) {
console.log("First Directive Data: " + args);
});
$rootScope.$broadcast("OnChildDirectiveCreated", {
"message": "I'm second directive",
"id": "secondDirective"
});
}
}
})
и первая директива:
angular.module("app").directive("first", function($rootScope){
return {
template: "First Directive",
link:function(scope,element,attribute){
$rootScope.$on("OnChildDirectiveCreated", function(event, args) {
$rootScope.$broadcast(args.id, someData);
});
}
}
})
Поскольку вы используете родительскую дочернюю структуру, всегда гарантируется, что первая директива будет готова, когда дочерние директивы будут готовы. Используя это решение, вы можете использовать многие дочерние директивы. Надеюсь, это поможет!