angularjs - llamar - ¿Cuál es la mejor manera de cancelar la propagación de eventos entre llamadas ng-click anidadas?
llamar funcion angular desde html (9)
A veces, puede tener más sentido hacer esto:
<widget ng-click="myClickHandler(); $event.stopPropagation()"/>
Elegí hacerlo de esta manera porque no quería que myClickHandler()
detuviera la propagación del evento en los muchos otros lugares donde se usó.
Claro, podría haber agregado un parámetro booleano a la función del controlador, pero stopPropagation()
es mucho más significativo que solo el true
.
Aquí hay un ejemplo. Digamos que quiero tener una superposición de imágenes como muchos sitios. Por lo tanto, cuando hace clic en una miniatura, aparece una superposición negra en toda su ventana, y una versión más grande de la imagen se centra en ella. Al hacer clic en la superposición negra lo descarta; hacer clic en la imagen llamará a una función que muestra la siguiente imagen.
El html:
<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
<img src="http://some_src" ng-click="nextImage()"/>
</div>
El javascript:
function OverlayCtrl($scope) {
$scope.hideOverlay = function() {
// Some code to hdie the overlay
}
$scope.nextImage = function() {
// Some code to find and display the next image
}
}
El problema es que con esta configuración, si hace clic en la imagen, se nextImage()
tanto nextImage()
como hideOverlay()
. Pero lo que quiero es que solo se nextImage()
.
Sé que puedes capturar y cancelar el evento en la función nextImage()
como esta:
if (window.event) {
window.event.stopPropagation();
}
... Pero quiero saber si hay una mejor manera de hacerlo en AngularJS que no me obligue a poner como prefijo todas las funciones en los elementos dentro de la superposición con este fragmento.
EN uso del controlador
$ scope.methodName = function (event) {event.stopPropagation ();}
Esto funciona para mí:
<a href="" ng-click="doSomething($event)">Action</a>
this.doSomething = function($event) {
$event.stopPropagation();
$event.preventDefault();
};
Lo que dijo @JosephSilber, o pasar el objeto $ event a ng-click
callback y detener la propagación dentro de él:
<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
<img src="http://some_src" ng-click="nextImage($event)"/>
</div>
$scope.nextImage = function($event) {
$event.stopPropagation();
// Some code to find and display the next image
}
Me gusta la idea de usar una directiva para esto:
.directive(''stopEvent'', function () {
return {
restrict: ''A'',
link: function (scope, element, attr) {
element.bind(''click'', function (e) {
e.stopPropagation();
});
}
};
});
Luego usa la directiva como:
<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
<img src="http://some_src" ng-click="nextImage()" stop-event/>
</div>
Si quisiera, podría hacer que esta solución sea más genérica, como esta respuesta a una pregunta diferente: https://.com/a/14547223/347216
Puede registrar otra directiva además de ng-click
que modifica el comportamiento predeterminado de ng-click
y detiene la propagación del evento. De esta forma no tendrías que agregar $event.stopPropagation
a mano.
app.directive(''ngClick'', function() {
return {
restrict: ''A'',
compile: function($element, attr) {
return function(scope, element, attr) {
element.on(''click'', function(event) {
event.stopPropagation();
});
};
}
}
});
Si inserta ng-click = "$ event.stopPropagation" en el elemento principal de su plantilla, se detendrá el stopPropogation a medida que suba el árbol, por lo que solo tendrá que escribirlo una vez para toda su plantilla.
Si no desea tener que agregar la propagación de detención a todos los enlaces, esto también funciona. Un poco más escalable.
$scope.hideOverlay( $event ){
// only hide the overlay if we click on the actual div
if( $event.target.className.indexOf(''overlay'') )
// hide overlay logic
}
Use $event.stopPropagation()
:
<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
<img src="http://some_src" ng-click="nextImage(); $event.stopPropagation()" />
</div>
Aquí hay una demostración: http://plnkr.co/edit/3Pp3NFbGxy30srl8OBmQ?p=preview