J'ai une directive que j'aimerais qu'une autre directive puisse appeler. J'ai essayé d'utiliser des contrôleurs directifs pour y parvenir.
La directive un serait assise sur la même page que la directive deux, et la directive un appellerait les méthodes exposées par le contrôleur de la directive deux:
Directive 1:
'use strict';
angular.module('angularTestApp')
.directive('fileLibrary', function () {
return {
templateUrl: 'views/manage/file_library/file-library.html',
require: 'videoClipDetails',
restrict: 'AE',
link: function postLink(scope, element, attrs, videClipDetailsCtrl) {
scope.doSomethingInVideoClipDirective = function() {
videClipDetailsCtrl.doSomething();
}
}
};
});
Directive deux:
'use strict';
angular.module('angularTestApp')
.directive('videoClipDetails', function () {
return {
templateUrl: 'views/video_clip/video-clip-details.html',
restrict: 'AE',
controller: function($scope, $element) {
this.doSomething = function() {
console.log('I did something');
}
},
link: function postLink(scope, element, attrs) {
console.log('videoClipDetails directive');
//start the element out as hidden
}
};
});
Fichier où les deux sont utilisés et configurés en tant que frères et sœurs:
<div>
<div video-clip-details></div>
<!-- main component for the file library -->
<div file-library></div>
</div>
Je sais que la lecture de la documentation que j'ai prise que les contrôleurs peuvent être partagés lorsque les directives sont sur le même élément, ce qui me fait penser que je pourrais regarder ce problème dans le mauvais sens. Quelqu'un peut-il me mettre sur la bonne voie?
Depuis angular.js documentation sur les directives
Lorsqu'une directive utilise
require
,$compile
générera une erreur sauf si le contrôleur spécifié est trouvé. Le^
le préfixe signifie que cette directive recherche le contrôleur sur ses parents (sans le^
préfixe, la directive ne recherchera le contrôleur que sur son propre élément).
Donc, fondamentalement, ce que vous essayez de faire pour que les frères et sœurs communiquent directement n'est pas possible. J'avais rencontré ce même problème mais je ne voulais pas utiliser un service de communication. J'ai trouvé une méthode d'utilisation d'une directive parent pour gérer la communication entre ses enfants, qui sont des frères et sœurs. J'ai posté l'exemple sur github .
Ce qui se passe, c'est que les deux enfants ont besoin du parent (require: '^parentDirective'
) et leur propre contrôleur, tous deux transmis à la fonction de liaison. À partir de là, chaque enfant peut obtenir une référence au contrôleur parent et à toutes ses méthodes publiques, comme une sorte d'API.
Ci-dessous, l'un des enfants itemEditor
function itemEditor() {
var directive = {
link: link,
scope: {},
controller: controller,
controllerAs: 'vm',
require: ['^itemManager', 'itemEditor'],
templateUrl: 'app/scripts/itemManager/itemManager.directives.itemEditor.html',
restrict: 'A'
};
return directive;
function link(scope, element, attrs, controllers) {
var itemManagerController = controllers[0];
var itemEditorController = controllers[1];
itemEditorController.itemManager = itemManagerController;
itemEditorController.initialize();
}
function controller() {
var vm = this;
// Properties
vm.itemManager = {};
vm.item = { id: -1, name: "", size: "" };
// Methods
vm.initialize = initialize;
vm.updateItem = updateItem;
vm.editItem = editItem;
// Functions
function initialize() {
vm.itemManager.respondToEditsWith(vm.editItem);
}
function updateItem() {
vm.itemManager.updateItem(vm.item);
vm.item = {};
}
function editItem(item) {
vm.item.id = item.id;
vm.item.name = item.name;
vm.item.size = item.size;
}
}
}
Notez que les valeurs passées dans le tableau require
sont le nom de la directive parent et le nom de la directive actuelle. Celles-ci sont alors toutes deux accessibles dans la fonction link
via le paramètre controllers
. Attribuez le contrôleur de la directive parent en tant que propriété de l'enfant actuel, puis il est accessible dans les fonctions de contrôleur de l'enfant via cette propriété.
Notez également comment dans la fonction link
de la directive enfant j'appelle une fonction initialize
depuis le contrôleur de l'enfant. C'est là qu'une partie des lignes de communication est établie.
Je dis essentiellement que chaque fois que vous (directive parent) recevez une demande de modification d'un élément, utilisez cette méthode nommée editItem
qui prend un item
comme paramètre.
Voici la directive parent
function itemManager() {
var directive = {
link: link,
controller: controller,
controllerAs: 'vm',
templateUrl: 'app/scripts/itemManager/itemManager.directives.itemManager.html',
restrict: 'A'
};
return directive;
function link(scope, element, attrs, controller) {
}
function controller() {
var vm = this;
vm.updateMethod = null;
vm.editMethod = null;
vm.updateItem = updateItem;
vm.editItem = editItem;
vm.respondToUpdatesWith = respondToUpdatesWith;
vm.respondToEditsWith = respondToEditsWith;
function updateItem(item) {
vm.updateMethod(item);
}
function editItem(item) {
vm.editMethod(item);
}
function respondToUpdatesWith(method) {
vm.updateMethod = method;
}
function respondToEditsWith(method) {
vm.editMethod = method;
}
}
}
Ici, dans le parent, vous pouvez voir que respondToEditsWith
prend une méthode comme paramètre et assigne cette valeur à sa propriété editMethod
. Cette propriété est appelée chaque fois que la méthode editItem
du contrôleur est appelée et que l'objet item
lui est transmis, appelant ainsi la méthode editItem
de la directive enfant. De même, l'enregistrement des données fonctionne de la même manière en sens inverse.
Mise à jour : Au fait, voici n article de blog sur coderwall.com où j'ai eu l'idée originale avec de bons exemples de require
et options de contrôleur dans les directives. Cela dit, sa syntaxe recommandée pour le dernier exemple de ce message n'a pas fonctionné pour moi, c'est pourquoi j'ai créé l'exemple que je référence ci-dessus.
Il n'y a aucun moyen réel d'exiger de communiquer entre les éléments frères de la manière que vous essayez de faire ici. Le require fonctionne comme vous l'avez configuré si les deux directives sont sur le même élément .
Cependant, vous ne pouvez pas le faire car vos deux directives ont un templateUrl associé que vous souhaitez utiliser, et vous ne pouvez en avoir qu'un par élément.
Vous pouvez cependant structurer votre html légèrement différemment pour que cela fonctionne. Vous devez essentiellement mettre une directive à l'intérieur de l'autre (transclus) et utiliser require: '^videoClipDetails'
. Cela signifie qu'il cherchera le parent pour le trouver. J'ai mis en place un violon pour le démontrer: http://jsfiddle.net/WwCvQ/1/
C'est le code qui fait fonctionner la chose parent:
// In videoClipDetails
template: '<div>clip details<div ng-transclude></div></div>',
transclude: 'true',
...
// in markup
<div video-clip-details>
<div file-library></div>
</div>
// in fileLibrary
require: '^videoClipDetails',
faites moi savoir si vous avez des questions!