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 updateMap()
a una acción del usuario. El botón de acción no está en la directiva.
¿Cuál es la mejor manera de llamar updateMap()
desde un controlador?
angularjs
angularjs-directive
mcbjam
fuente
fuente
Respuestas:
Si desea utilizar ámbitos aislados, puede pasar un objeto de control utilizando el enlace bidireccional
=
de una variable desde el ámbito del controlador. También puede controlar varias instancias de la misma directiva en una página con el mismo objeto de control.fuente
scope.control
exista, de lo contrario, otros lugares que usan la directiva pero no necesitan acceder a los métodos de la directiva y no tienen uncontrol
atributo comenzarán a arrojar errores sobre no poder establecer atributosundefined
Suponiendo que el botón de acción utiliza el mismo controlador
$scope
como la Directiva, simplemente definir la funciónupdateMap
en$scope
el interior de la función de enlace. Su controlador puede llamar a esa función cuando se hace clic en el botón de acción.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 hacerlo funcionar: agregue un
set-fn
atributo a lamap
directiva que registrará la función de la directiva con el controlador:fiddle
fuente
scope
propiedad en la declaración de directiva.Aunque puede ser tentador exponer un objeto en el ámbito aislado de una directiva para facilitar la comunicación con él, hacerlo puede llevar a un código confuso de "espagueti", especialmente si necesita encadenar esta comunicación a través de un par de niveles (controlador, directiva, a la directiva anidada, etc.)
Originalmente seguimos este camino, pero después de más investigaciones descubrimos que tenía más sentido y dio como resultado 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 necesite reaccionar a esos cambios para la comunicación.
Esta abstracción funciona muy bien con el marco de inyección de dependencia 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 eventos en un ámbito aislado.
Por último, en el caso de que necesite comunicarse entre directivas que dependen unas de otras, recomendaría compartir un controlador entre esas directivas como medio de comunicación.
El Wiki de AngularJS para Mejores Prácticas también menciona esto:
fuente
=
, la variable contiene el nombre del método y los argumentos. (2) exponga una cadena de enlace unidireccional@
como identificación del tema y deje que el destinatario envíe un evento sobre este tema. Ahora vi la wiki de mejores prácticas. Creo que hay razones para no hacerlo de una manera u otra. Pero todavía no tengo muy claro cómo funciona. En mi caso, creé una directiva de tabset, quiero exponer unswitchTab(tabIndex)
método. ¿Podría dar un ejemplo más?switchTab(tabIndex)
método, solo te unirías a unatabIndex
variable. Su controlador de página puede tener acciones que cambien esa variable. Vincula / pasa esa variable a la pestaña Directiva. Su directiva de pestañas puede ver esa variable en busca de cambios y realizar switchTab por sí mismo. Porque la directiva decide cuándo / cómo controlar sus pestañas en función de una variable. Ese no es el trabajo de una fuente externa, de lo contrario, las fuentes externas requieren conocimiento del funcionamiento interno de la directiva, lo cual es malo.Sobre la base de la respuesta de Oliver: es posible que no siempre necesite 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
atributo a la directiva solo para evitar que arroje 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.
Agregaría un cheque para asegurarme de que
scope.control
existe, y establecería métodos de manera similar al patrón del módulo reveladorfuente
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 (gerente)
Este método es independiente de si las directivas
$scope
son compartidas o aisladas.A
factory
para registrar las instancias de la directivaEl código de la directiva, generalmente 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
código de plantilla
Acceda a la instancia del controlador utilizando
factory
y ejecute los métodos expuestos públicamenteEnfoque angular
Sacando una hoja del libro de angular sobre cómo tratan
usando $ parse y registrando el controlador en el
$parent
alcance. Esta técnica no funciona en$scope
directivas aisladas .Acceda dentro del controlador usando
$scope.foo
fuente
$scope.foo
debería ser$scope.my_form
$scope.foo
porque nuestra plantilla es<div my-directive name="foo"></div>
yname
el valor del atributo es 'foo'.<form
es solo un ejemplo de una de las directivas angulares que emplea esta técnicaUn 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.
Cree una API para comunicarse con la directiva. AddUpdateEvent agrega un evento a la matriz de eventos y updateMap llama a cada función de evento.
(Quizás tenga que agregar funcionalidad para eliminar el evento).
En la directiva, establezca una referencia a MapAPI y agregue $ scope.updateMap como evento cuando se llame a MapApi.updateMap.
En el controlador "principal", agregue una referencia al MapApi y simplemente llame a MapApi.updateMap () para actualizar el mapa.
fuente
Puede especificar un atributo DOM que se puede usar para permitir que la directiva defina una función en el ámbito primario. El ámbito principal puede llamar a este método como cualquier otro. Aquí hay un saqueador. Y a continuación se muestra el código relevante.
clearfn
es un atributo en el elemento directivo en el que el ámbito primario puede pasar una propiedad de ámbito que la directiva puede establecer en una función que logre el comportamiento deseado.fuente
scope: { clearFn: '=clearfn' }
).Simplemente use el alcance. $ Parent para asociar la función llamada a la función directiva
en HTML
fuente
Puede indicar el nombre del método a la directiva para definir a qué desea llamar desde el controlador pero sin aislar el alcance,
fuente
PROBADO Espero que esto ayude a alguien.
Mi enfoque simple (Piensa en las etiquetas como tu código original)
fuente
Quizás esta no sea la mejor opción, pero puede hacerlo
angular.element("#element").isolateScope()
o$("#element").isolateScope()
acceder al alcance y / o al controlador de su directiva.fuente
Cómo obtener el controlador de una directiva en un controlador de página:
escriba una directiva personalizada para obtener la referencia al controlador de la directiva desde el elemento DOM:
utilízalo en el controlador html de la página:
Use el controlador directivo en el controlador de página:
Nota: la solución dada funciona solo para los controladores de las directivas de elementos (el nombre de la etiqueta se usa para obtener el nombre de la directiva deseada).
fuente
La siguiente solución será útil cuando tenga controladores (padre y directiva (aislados)) en formato 'controlador como'
alguien puede encontrar esto útil,
directiva:
controlador directivo:
código HTML :
fuente