Detenga la propagación de un clic ng subyacente dentro de un evento de clic de jQuery

Un dropdown Twitter Bootstrap está nested dentro de un tr . El tr se puede hacer clic a través de ng-click . Al hacer clic en cualquier lugar de la página, se contraerá el menú desplegable. Ese comportamiento se define en una directiva a través de $document.bind('click', closeMenu) .

Entonces, cuando se abre el menú y el usuario hace clic en una fila, quiero que el menú se cierre (como lo hace) Y quiero evitar el evento de clic en la fila.

JSFiddle: http://jsfiddle.net/LMc2f/1/
Directiva JSFiddle + en línea : http://jsfiddle.net/9DM8U/1/

Código relevante de ui-bootstrap-tpls-0.10.0.js:

 angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) { var openElement = null, closeMenu = angular.noop; return { restrict: 'CA', link: function(scope, element, attrs) { scope.$watch('$location.path', function() { closeMenu(); }); element.parent().bind('click', function() { closeMenu(); }); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; $document.bind('click', closeMenu); } }); } }; }]); 

No puedo descubrir cómo detener el evento subyacente de ng-click dentro de closeMenu .

NOTA: No puedo encontrar una manera de acceder a $event por lo que no he podido probar $event.stopPropagation() .

La directiva desplegable vincula el evento de clic en el documento, pero al hacer clic en la fila, el evento comienza a propagarse desde el elemento de destino hasta el nodo del documento raíz ( td -> tr -> table -> document ).

Por eso es que siempre se llama a su controlador de ng-click , que tiene en su fila, a pesar de que la directiva “detiene” la burbuja en el clic del documento.

La solución es utilizar el indicador useCapture al agregar el controlador de clic para el documento.

Después de iniciar la captura, todos los eventos del tipo especificado se enviarán al oyente registrado antes de enviarse a cualquier EventTarget debajo de él en el árbol DOM. mdn

Ahora, para indicar a la directiva desplegable que use su propio controlador, debe cambiar la fuente de la directiva. Pero es una directiva de terceros, y probablemente no quiera hacerlo, por razones de mantenimiento.

Aquí es donde entra en acción el poderoso $ decorator angular. Puede usar el $ decorator para cambiar la fuente del módulo de terceros sobre la marcha, sin tocar realmente los archivos de origen reales.

Por lo tanto, con el decorador en su lugar y el controlador de eventos personalizado en el nodo de documento, esta es la forma en que puede hacer que el menú desplegable se comporte:

VIOLÍN

 var myApp = angular.module('myApp', []); /** * Original dropdownToggle directive from ui-bootstrap. * Nothing changed here. */ myApp.directive('dropdownToggle', ['$document', '$location', function ($document, $location) { var openElement = null, closeMenu = angular.noop; return { restrict: 'CA', link: function(scope, element, attrs) { scope.$watch('$location.path', function() { closeMenu(); }); element.parent().bind('click', function() { closeMenu(); }); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; $document.bind('click', closeMenu); /* <--- CAUSE OF ALL PROBLEMS ----- */ } }); } }; }]); /** * This is were we decorate the dropdownToggle directive * in order to change the way the document click handler works */ myApp.config(function($provide){ 'use strict'; $provide.decorator('dropdownToggleDirective', [ '$delegate', '$document', function ($delegate, $document) { var directive = $delegate[0]; var openElement = null; var closeMenu = angular.noop; function handler(e){ var elm = angular.element(e.target); if(!elm.parents('.dropdown-menu').length){ e.stopPropagation(); e.preventDefault(); } closeMenu(); // After closing the menu, we remove the all-seeing handler // to allow the application click events to work nnormally $document[0].removeEventListener('click', handler, true); } directive.compile = function(){ return function(scope, element) { scope.$watch('$location.path', closeMenu); element.parent().bind('click', closeMenu); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; // We attach the click handler by specifying the third "useCapture" parameter as true $document[0].addEventListener('click', handler, true); } }); }; }; return $delegate; } ]); }); 

ACTUALIZAR:

Tenga en cuenta que el controlador personalizado actualizado evitará la propagación a menos que el elemento de destino sea la opción desplegable real. Esto solucionará el problema en el que se impedía el evento de clic incluso al hacer clic en las opciones desplegables.

Esto todavía no evitará que el evento se reduzca a la fila (desde la opción desplegable), pero esto es algo que no está relacionado de ninguna manera con la directiva desplegable. De todos modos, para evitar este burbujeo, puede pasar el objeto $event a la función de expresión ng-click y usar ese objeto para detener la uniformidad a la fila de la tabla:

 
 function DropdownCtrl($scope) { $scope.items = [ "Action", "Another action", "Something else here" ]; $scope.clicked = function(what, event) { alert(what + ' clicked'); if(event){ event.stopPropagation(); event.preventDefault(); } } } 

Me inclino por llamar a $event.stopPropagation() desde la propia plantilla. La lógica relacionada con los eventos probablemente pertenece allí. También debería facilitar las pruebas unitarias. Alguien que esté mirando la plantilla también sabrá que el evento no se disparó sin mirar el controlador subyacente.

 

debe pasar el evento de ng-click en la línea 2 de su violín, y luego haga preventDefault y stopPropigation en ese objeto dentro de su método do

  
    Intereting Posts