por personalizadas para nombre directivas código cuál crear archivo angularjs angularjs-directive

angularjs - para - directivas personalizadas angular 5



¿Cómo llamar a un método definido en una directiva AngularJS? (13)

Tengo una directiva, aquí está el código:

.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); } } })

Me gustaría llamar a updateMap() en una acción de usuario. El botón de acción no está en la directiva.

¿Cuál es la mejor manera de llamar a updateMap() desde un controlador?


Aunque podría ser tentador exponer un objeto en el ámbito aislado de una directiva para facilitar la comunicación con él, hacerlo puede generar un código de "espagueti" confuso, especialmente si necesita encadenar esta comunicación a través de un par de niveles (controlador, a directiva, a directiva anidada, etc.)

Originalmente tomamos este camino, pero luego de una investigación más, descubrimos que tenía más sentido y resultó en un código más fácil de mantener y legible para exponer eventos y propiedades que una directiva usará para la comunicación a través de un servicio y luego usar $ watch en las propiedades de ese servicio en La directiva o cualquier otro control que deba reaccionar a esos cambios para la comunicación.

Esta abstracción funciona muy bien con el marco de inyección de dependencias de AngularJS, ya que puede inyectar el servicio en cualquier elemento que necesite reaccionar ante esos eventos. Si observa el archivo Angular.js, verá que las directivas allí también usan servicios y $ watch de esta manera, no exponen los eventos en el ámbito aislado.

Por último, en el caso de que necesite comunicarse entre directivas que dependan unas de otras, recomendaría compartir un controlador entre esas directivas como medio de comunicación.

La Wiki de Mejores Prácticas de AngularJS también menciona esto:

Utilice. $ Broadcast (),. $ Emit () y. $ On () para eventos atómicos Eventos que son relevantes a nivel mundial en toda la aplicación (como la autenticación de un usuario o el cierre de la aplicación). Si desea eventos específicos de módulos, servicios o widgets, debe considerar Servicios, Controladores Directivos o Libs de terceros.

  • $ scope. $ watch () debería reemplazar la necesidad de eventos
  • Los servicios de inyección y los métodos de llamada directamente también son útiles para la comunicación directa
  • Las directivas pueden comunicarse directamente entre sí a través de los controladores de directivas

Basándose en la respuesta de Oliver, es posible que no siempre tenga que acceder a los métodos internos de una directiva, y en esos casos probablemente no desee tener que crear un objeto en blanco y agregar un control a la directiva solo para evitar que se genere un error. ( cannot set property ''takeTablet'' of undefined ).

También es posible que desee utilizar el método en otros lugares dentro de la directiva.

Me gustaría agregar una verificación para asegurarme de que scope.control exista, y configurar los métodos de manera similar al patrón del módulo revelador.

app.directive(''focusin'', function factory() { return { restrict: ''E'', replace: true, template: ''<div>A:{{control}}</div>'', scope: { control: ''='' }, link : function (scope, element, attrs) { var takenTablets = 0; var takeTablet = function() { takenTablets += 1; } if (scope.control) { scope.control = { takeTablet: takeTablet }; } } }; });


Cómo obtener el controlador de una directiva en un controlador de página:

  1. escriba una directiva personalizada para obtener la referencia al controlador de directivas desde el elemento DOM:

    angular.module(''myApp'') .directive(''controller'', controller); controller.$inject = [''$parse'']; function controller($parse) { var directive = { restrict: ''A'', link: linkFunction }; return directive; function linkFunction(scope, el, attrs) { var directiveName = attrs.$normalize(el.prop("tagName").toLowerCase()); var directiveController = el.controller(directiveName); var model = $parse(attrs.controller); model.assign(scope, directiveController); } }

  2. Utilízalo en el html del controlador de página:

    <my-directive controller="vm.myDirectiveController"></my-directive>

  3. Utilice el controlador de directivas en el controlador de página:

    vm.myDirectiveController.callSomeMethod();

Nota: la solución dada solo funciona para los controladores de las directivas de elementos (el nombre de la etiqueta se usa para obtener el nombre de la directiva deseada).


La solución a continuación será útil cuando tenga controladores (principal y directivo (aislados)) en formato ''controlador como''

alguien podría encontrar esto útil,

directiva:

var directive = { link: link, restrict: ''E'', replace: true, scope: { clearFilters: ''='' }, templateUrl: "/temp.html", bindToController: true, controller: ProjectCustomAttributesController, controllerAs: ''vmd'' }; return directive; function link(scope, element, attrs) { scope.vmd.clearFilters = scope.vmd.SetFitlersToDefaultValue; } }

Controlador directivo:

function DirectiveController($location, dbConnection, uiUtility) { vmd.SetFitlersToDefaultValue = SetFitlersToDefaultValue; function SetFitlersToDefaultValue() { //your logic } }

código HTML :

<Test-directive clear-filters="vm.ClearFilters"></Test-directive> <a class="pull-right" style="cursor: pointer" ng-click="vm.ClearFilters()"><u>Clear</u></a> //this button is from parent controller which will call directive controller function


Para ser honesto, no estaba realmente convencido con ninguna de las respuestas en este hilo. Entonces, aquí están mis soluciones:

Enfoque de manejador de directivas (administrador)

Este método es independiente de si el $scope la directiva es compartido o aislado.

Una factory para registrar las instancias directivas.

angular.module(''myModule'').factory(''MyDirectiveHandler'', function() { var instance_map = {}; var service = { registerDirective: registerDirective, getDirective: getDirective, deregisterDirective: deregisterDirective }; return service; function registerDirective(name, ctrl) { instance_map[name] = ctrl; } function getDirective(name) { return instance_map[name]; } function deregisterDirective(name) { instance_map[name] = null; } });

El código de la directiva, por lo general pongo toda la lógica que no trata con DOM dentro del controlador de la directiva. Y registrando la instancia del controlador dentro de nuestro controlador.

angular.module(''myModule'').directive(''myDirective'', function(MyDirectiveHandler) { var directive = { link: link, controller: controller }; return directive; function link() { //link fn code } function controller($scope, $attrs) { var name = $attrs.name; this.updateMap = function() { //some code }; MyDirectiveHandler.registerDirective(name, this); $scope.$on(''destroy'', function() { MyDirectiveHandler.deregisterDirective(name); }); } })

código de plantilla

<div my-directive name="foo"></div>

Acceda a la instancia del controlador utilizando la factory y ejecute los métodos expuestos públicamente

angular.module(''myModule'').controller(''MyController'', function(MyDirectiveHandler, $scope) { $scope.someFn = function() { MyDirectiveHandler.get(''foo'').updateMap(); }; });

Enfoque angular

Tomando una hoja del libro de Angular sobre cómo lidian con

<form name="my_form"></form>

usando $parse y registrando el controlador en el alcance de $parent . Esta técnica no funciona en directivas aisladas de $scope .

angular.module(''myModule'').directive(''myDirective'', function($parse) { var directive = { link: link, controller: controller, scope: true }; return directive; function link() { //link fn code } function controller($scope, $attrs) { $parse($attrs.name).assign($scope.$parent, this); this.updateMap = function() { //some code }; } })

Acceda dentro del controlador usando $scope.foo

angular.module(''myModule'').controller(''MyController'', function($scope) { $scope.someFn = function() { $scope.foo.updateMap(); }; });


Puede especificar un atributo DOM que se puede usar para permitir que la directiva defina una función en el ámbito principal. El ámbito primario puede entonces llamar a este método como cualquier otro. Here''s un plunker. Y debajo está el código relevante.

clearfn es un atributo en el elemento de directiva en el que el ámbito principal puede pasar una propiedad de ámbito que la directiva puede configurar a una función que cumple con el comportamiento deseado.

<!DOCTYPE html> <html ng-app="myapp"> <head> <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script> <link rel="stylesheet" href="style.css" /> <style> my-box{ display:block; border:solid 1px #aaa; min-width:50px; min-height:50px; padding:.5em; margin:1em; outline:0px; box-shadow:inset 0px 0px .4em #aaa; } </style> </head> <body ng-controller="mycontroller"> <h1>Call method on directive</h1> <button ng-click="clear()">Clear</button> <my-box clearfn="clear" contentEditable=true></my-box> <script> var app = angular.module(''myapp'', []); app.controller(''mycontroller'', function($scope){ }); app.directive(''myBox'', function(){ return { restrict: ''E'', scope: { clearFn: ''=clearfn'' }, template: '''', link: function(scope, element, attrs){ element.html(''Hello World!''); scope.clearFn = function(){ element.html(''''); }; } } }); </script> </body> </html>


Puede indicar el nombre del método a la directiva para definir a qué desea llamar desde el controlador pero sin aislar el alcance,

angular.module("app", []) .directive("palyer", [ function() { return { restrict: "A", template:''<div class="player"><span ng-bind="text"></span></div>'', link: function($scope, element, attr) { if (attr.toPlay) { $scope[attr.toPlay] = function(name) { $scope.text = name + " playing..."; } } } }; } ]) .controller("playerController", ["$scope", function($scope) { $scope.clickPlay = function() { $scope.play(''AR Song''); }; } ]);

.player{ border:1px solid; padding: 10px; }

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <div ng-controller="playerController"> <p>Click play button to play <p> <p palyer="" to-play="play"></p> <button ng-click="clickPlay()">Play</button> </div> </div>


Quizás esta no sea la mejor opción, pero puede hacer angular.element("#element").isolateScope() o $("#element").isolateScope() para acceder al alcance y / o al controlador de su directiva.


Si desea utilizar ámbitos aislados, puede pasar un objeto de control utilizando el enlace bidireccional = de una variable del ámbito del controlador. También puede controlar varias instancias de la misma directiva en una página con el mismo objeto de control.

angular.module(''directiveControlDemo'', []) .controller(''MainCtrl'', function($scope) { $scope.focusinControl = {}; }) .directive(''focusin'', function factory() { return { restrict: ''E'', replace: true, template: ''<div>A:{{internalControl}}</div>'', scope: { control: ''='' }, link: function(scope, element, attrs) { scope.internalControl = scope.control || {}; scope.internalControl.takenTablets = 0; scope.internalControl.takeTablet = function() { scope.internalControl.takenTablets += 1; } } }; });

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="directiveControlDemo"> <div ng-controller="MainCtrl"> <button ng-click="focusinControl.takeTablet()">Call directive function</button> <p> <b>In controller scope:</b> {{focusinControl}} </p> <p> <b>In directive scope:</b> <focusin control="focusinControl"></focusin> </p> <p> <b>Without control object:</b> <focusin></focusin> </p> </div> </div>


Simplemente use scope. $ Parent para asociar la función llamada a la función directiva

angular.module(''myApp'', []) .controller(''MyCtrl'',[''$scope'',function($scope) { }]) .directive(''mydirective'',function(){ function link(scope, el, attr){ //use scope.$parent to associate the function called to directive function scope.$parent.myfunction = function directivefunction(parameter){ //do something } } return { link: link, restrict: ''E'' }; });

en HTML

<div ng-controller="MyCtrl"> <mydirective></mydirective> <button ng-click="myfunction(parameter)">call()</button> </div>


Suponiendo que el botón de acción utiliza el mismo $scope controlador que la directiva, simplemente defina la función updateMap en $scope dentro de la función de enlace. Su controlador puede entonces llamar a esa función cuando se hace clic en el botón de acción.

<div ng-controller="MyCtrl"> <map></map> <button ng-click="updateMap()">call updateMap()</button> </div>

app.directive(''map'', function() { return { restrict: ''E'', replace: true, template: ''<div></div>'', link: function($scope, element, attrs) { $scope.updateMap = function() { alert(''inside updateMap()''); } } } });

fiddle

Según el comentario de @FlorianF, si la directiva usa un alcance aislado, las cosas son más complicadas. Aquí hay una manera de hacer que funcione: agregue un atributo set-fn a la directiva de map que registrará la función de directiva con el controlador:

<map set-fn="setDirectiveFn(theDirFn)"></map> <button ng-click="directiveFn()">call directive function</button>

scope: { setFn: ''&'' }, link: function(scope, element, attrs) { scope.updateMap = function() { alert(''inside updateMap()''); } scope.setFn({theDirFn: scope.updateMap}); }

function MyCtrl($scope) { $scope.setDirectiveFn = function(directiveFn) { $scope.directiveFn = directiveFn; }; }

fiddle


Un poco tarde, pero esta es una solución con el alcance aislado y los "eventos" para llamar a una función en la directiva. Esta solución está inspirada en esta publicación SO de satchmorun y agrega un módulo y una API.

//Create module var MapModule = angular.module(''MapModule'', []); //Load dependency dynamically angular.module(''app'').requires.push(''MapModule'');

Crear una API para comunicarse con la directiva. El addUpdateEvent agrega un evento a la matriz de eventos y updateMap llama a cada función de evento.

MapModule.factory(''MapApi'', function () { return { events: [], addUpdateEvent: function (func) { this.events.push(func); }, updateMap: function () { this.events.forEach(function (func) { func.call(); }); } } });

(Tal vez tenga que agregar funcionalidad para eliminar el evento).

En la directiva, establezca una referencia a MapAPI y agregue $ scope.updateMap como un evento cuando se llame a MapApi.updateMap.

app.directive(''map'', function () { return { restrict: ''E'', scope: {}, templateUrl: ''....'', controller: function ($scope, $http, $attrs, MapApi) { $scope.api = MapApi; $scope.updateMap = function () { //Update the map }; //Add event $scope.api.addUpdateEvent($scope.updateMap); } } });

En el controlador "principal", agregue una referencia al MapApi y solo llame a MapApi.updateMap () para actualizar el mapa.

app.controller(''mainController'', function ($scope, MapApi) { $scope.updateMapButtonClick = function() { MapApi.updateMap(); }; }


Probado Espero que esto ayude a alguien.

Mi enfoque simple (piense en las etiquetas como su código original)

<html> <div ng-click="myfuncion"> <my-dir callfunction="myfunction"> </html> <directive "my-dir"> callfunction:"=callfunction" link : function(scope,element,attr) { scope.callfunction = function() { /// your code } } </directive>