J'ai une directive, voici le code:
.directive('map', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function($scope, element, attrs) {
var center = new google.maps.LatLng(50.1, 14.4);
$scope.map_options = {
zoom: 14,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(attrs.id), $scope.map_options);
var dirService= new google.maps.DirectionsService();
var dirRenderer= new google.maps.DirectionsRenderer()
var showDirections = function(dirResult, dirStatus) {
if (dirStatus != google.maps.DirectionsStatus.OK) {
alert('Directions failed: ' + dirStatus);
return;
}
// Show directions
dirRenderer.setMap(map);
//$scope.dirRenderer.setPanel(Demo.dirContainer);
dirRenderer.setDirections(dirResult);
};
// Watch
var updateMap = function(){
dirService.route($scope.dirRequest, showDirections);
};
$scope.$watch('dirRequest.origin', updateMap);
google.maps.event.addListener(map, 'zoom_changed', function() {
$scope.map_options.zoom = map.getZoom();
});
dirService.route($scope.dirRequest, showDirections);
}
}
})
Je voudrais appeler updateMap()
une action utilisateur. Le bouton d'action n'est pas sur la directive.
Quelle est la meilleure façon d'appeler à updateMap()
partir d'un contrôleur?
Réponses:
Si vous souhaitez utiliser des étendues isolées, vous pouvez passer un objet de contrôle à l'aide de la liaison bidirectionnelle
=
d'une variable de la portée du contrôleur. Vous pouvez également contrôler plusieurs instances de la même directive sur une page avec le même objet de contrôle.la source
scope.control
existe, sinon d'autres endroits qui utilisent la directive mais n'ont pas besoin d'accéder aux méthodes de la directive et n'ont pas d'control
attr commenceront à générer des erreurs de ne pas pouvoir définir d'attributs surundefined
En supposant que le bouton d'action utilise le même contrôleur
$scope
que la directive, définissez simplement la fonctionupdateMap
à l'$scope
intérieur de la fonction de liaison. Votre contrôleur peut alors appeler cette fonction lorsque vous cliquez sur le bouton d'action.fiddle
Selon le commentaire de @ FlorianF, si la directive utilise une portée isolée, les choses sont plus compliquées. Voici une façon de le faire fonctionner: ajoutez un
set-fn
attribut à lamap
directive qui enregistrera la fonction directive auprès du contrôleur:fiddle
la source
scope
propriété dans la déclaration de directive.Bien qu'il puisse être tentant d'exposer un objet sur la portée isolée d'une directive pour faciliter la communication avec lui, cela peut conduire à confondre le code "spaghetti", surtout si vous avez besoin de chaîner cette communication à travers plusieurs niveaux (contrôleur, à directive, à la directive imbriquée, etc.)
À l'origine, nous avons emprunté cette voie, mais après quelques recherches supplémentaires, cela a semblé plus logique et a abouti à un code à la fois plus maintenable et plus lisible pour exposer les événements et les propriétés qu'une directive utilisera pour la communication via un service, puis en utilisant $ watch sur les propriétés de ce service dans la directive ou tout autre contrôle qui devrait réagir à ces changements de communication.
Cette abstraction fonctionne très bien avec le cadre d'injection de dépendance d'AngularJS car vous pouvez injecter le service dans tous les éléments qui doivent réagir à ces événements. Si vous regardez le fichier Angular.js, vous verrez que les directives qui y figurent utilisent également les services et $ watch de cette manière, elles n'exposent pas les événements sur la portée isolée.
Enfin, dans le cas où vous devez communiquer entre des directives qui dépendent les unes des autres, je recommanderais de partager un contrôleur entre ces directives comme moyen de communication.
Le Wiki for Best Practices d'AngularJS mentionne également ceci:
la source
=
, la variable contient le nom de la méthode et les arguments. (2) exposer une chaîne de liaison unidirectionnelle en@
tant qu'ID de sujet et laisser l'appelé envoyer un événement sur ce sujet. Maintenant, j'ai vu le wiki des meilleures pratiques. Je pense qu'il y a une raison de ne pas le faire de la même manière. Mais je ne sais toujours pas très bien comment cela fonctionne. Dans mon cas, j'ai créé une directive tabset, je veux exposer uneswitchTab(tabIndex)
méthode. Pourriez-vous donner plus d'exemples?switchTab(tabIndex)
méthode, vous ne vous lieriez qu'à unetabIndex
variable. Votre contrôleur de page peut avoir des actions qui modifient cette variable. Vous liez / transmettez cette variable dans votre onglet Directive. Votre onglet Directive peut alors surveiller les modifications de cette variable et exécuter switchTab de son propre gré. Parce que la directive décide quand / comment contrôler ses onglets en fonction d'une variable. Ce n'est pas le travail d'une source externe, sinon les sources externes nécessitent une connaissance du fonctionnement interne de la directive, ce qui est mauvais m'kay.S'appuyant sur la réponse d'Oliver - vous n'aurez peut-être pas toujours besoin d'accéder aux méthodes internes d'une directive, et dans ces cas, vous ne voudrez probablement pas avoir à créer un objet vide et ajouter un
control
attr à la directive juste pour l'empêcher de générer une erreur (cannot set property 'takeTablet' of undefined
).Vous pouvez également souhaiter utiliser la méthode à d'autres endroits de la directive.
J'ajouterais une vérification pour m'assurer qu'il
scope.control
existe, et je définirais des méthodes similaires au modèle de module révélateurla source
Pour être honnête, je n'ai été vraiment convaincu par aucune des réponses de ce fil. Voici donc mes solutions:
Approche du gestionnaire de directives (gestionnaire)
Cette méthode est indépendante de si la directive
$scope
est partagée ou isoléeA
factory
pour enregistrer les instances de directiveLe code de directive, je mets généralement toute la logique qui ne traite pas du DOM à l'intérieur du contrôleur de directive. Et l'enregistrement de l'instance de contrôleur dans notre gestionnaire
code modèle
Accédez à l'instance de contrôleur à l'aide de
factory
& exécutez les méthodes exposées publiquementL'approche d'Angular
Prendre une feuille du livre d'Angular sur la façon dont ils gèrent
en utilisant $ parse et en enregistrant le contrôleur sur la
$parent
portée. Cette technique ne fonctionne pas sur des$scope
directives isolées .Accédez-y à l'intérieur du contrôleur en utilisant
$scope.foo
la source
$scope.foo
devrait être$scope.my_form
$scope.foo
puisque notre modèle est<div my-directive name="foo"></div>
etname
la valeur de l'attribut est 'foo'.<form
est juste un exemple de l'une des directives angulaires qui utilise cette techniqueUn peu tard, mais c'est une solution avec la portée isolée et les "événements" pour appeler une fonction dans la directive. Cette solution est inspirée de ce post SO de satchmorun et ajoute un module et une API.
Créez une API pour communiquer avec la directive. AddUpdateEvent ajoute un événement au tableau d'événements et updateMap appelle chaque fonction d'événement.
(Vous devrez peut-être ajouter des fonctionnalités pour supprimer l'événement.)
Dans la directive, définissez une référence à MapAPI et ajoutez $ scope.updateMap en tant qu'événement lorsque MapApi.updateMap est appelé.
Dans le contrôleur "principal", ajoutez une référence à MapApi et appelez simplement MapApi.updateMap () pour mettre à jour la carte.
la source
Vous pouvez spécifier un attribut DOM qui peut être utilisé pour permettre à la directive de définir une fonction sur la portée parent. La portée parent peut alors appeler cette méthode comme n'importe quelle autre. Voici un plongeur. Et ci-dessous est le code correspondant.
clearfn
est un attribut sur l'élément de directive dans lequel la portée parent peut passer une propriété de portée que la directive peut ensuite définir sur une fonction qui accomplit le comportement souhaité.la source
scope: { clearFn: '=clearfn' }
).Utilisez simplement scope. $ Parent pour associer la fonction appelée à la fonction directive
en HTML
la source
Vous pouvez indiquer le nom de la méthode à la directive pour définir celui que vous souhaitez appeler à partir du contrôleur, mais sans isoler la portée,
la source
TESTÉ J'espère que cela aide quelqu'un.
Mon approche simple (pensez aux balises comme votre code d'origine)
la source
Ce n'est peut-être pas le meilleur choix, mais vous pouvez le faire
angular.element("#element").isolateScope()
ou$("#element").isolateScope()
accéder à la portée et / ou au contrôleur de votre directive.la source
Comment obtenir le contrôleur d'une directive dans un contrôleur de page:
écrire une directive personnalisée pour obtenir la référence au contrôleur de directive à partir de l'élément DOM:
utilisez-le dans le html du contrôleur de page:
Utilisez le contrôleur de directive dans le contrôleur de page:
Remarque: la solution donnée ne fonctionne que pour les contrôleurs des directives d'élément (le nom de balise est utilisé pour obtenir le nom de la directive souhaitée).
la source
La solution ci-dessous sera utile lorsque vous avez des contrôleurs (parent et directive (isolés)) au format 'contrôleur en tant que'
quelqu'un pourrait trouver cela utile,
directive:
Contrôleur directif:
Code HTML :
la source