La direttiva a discesa AngularJS si nasconde quando si fa clic all’esterno

Sto provando a creare un elenco a discesa multiselect con l’opzione checkbox e filter. Sto cercando di hide la lista con un clic esterno, ma non riesco a capire come. Apprezzo il tuo aiuto.

http://plnkr.co/edit/tw0hLz68O8ueWj7uZ78c

Attenzione, la soluzione (il Plunker fornito nella domanda) non chiude i popup di altre windows quando si apre un secondo popup (su una pagina con selezioni multiple).

Cliccando su una casella per aprire un nuovo popup, l’evento click verrà sempre fermato. L’evento non raggiungerà mai nessun altro popup aperto (per chiuderli).

Ho risolto questo rimuovendo event.stopPropagation(); allineare e abbinare tutti gli elementi figlio del popup.

Il popup sarà chiuso solo se l’elemento events non corrisponde ad alcun elemento figlio del popup.

Ho cambiato il codice della direttiva al seguente:

select.html (codice direttiva)

 link: function(scope, element, attr){ scope.isPopupVisible = false; scope.toggleSelect = function(){ scope.isPopupVisible = !scope.isPopupVisible; } $(document).bind('click', function(event){ var isClickedElementChildOfPopup = element .find(event.target) .length > 0; if (isClickedElementChildOfPopup) return; scope.$apply(function(){ scope.isPopupVisible = false; }); }); } 

Ho biforcuto il plunk e ho applicato le modifiche:

Plunker: Nascondi popup div al clic all’esterno

Immagine dello schermo:

Screenshot Plunker

Questo è un vecchio post, ma nel caso in cui questo aiuti qualcuno qui è un esempio funzionante di click all’esterno che non si basa su nulla se non angular.

 module('clickOutside', []).directive('clickOutside', function ($document) { return { restrict: 'A', scope: { clickOutside: '&' }, link: function (scope, el, attr) { $document.on('click', function (e) { if (el !== e.target && !el[0].contains(e.target)) { scope.$apply(function () { scope.$eval(scope.clickOutside); }); } }); } } }); 

OK ho dovuto chiamare $ apply () perché l’evento sta accadendo fuori dal mondo angular (come da doc).

  element.bind('click', function(event) { event.stopPropagation(); }); $document.bind('click', function(){ scope.isVisible = false; scope.$apply(); }); 

L’ho capito ascoltando un evento di click globale in questo modo:

 .directive('globalEvents', ['News', function(News) { // Used for global events return function(scope, element) { // Listens for a mouse click // Need to close drop down menus element.bind('click', function(e) { News.setClick(e.target); }); } }]) 

L’evento stesso viene quindi trasmesso tramite un servizio di notizie

 angular.factory('News', ['$rootScope', function($rootScope) { var news = {}; news.setClick = function( target ) { this.clickTarget = target; $rootScope.$broadcast('click'); }; }]); 

È quindi ansible ascoltare la trasmissione ovunque sia necessario. Ecco una direttiva di esempio:

 .directive('dropdown', ['News', function(News) { // Drop down menu für the logo button return { restrict: 'E', scope: {}, link: function(scope, element) { var opened = true; // Toggles the visibility of the drop down menu scope.toggle = function() { element.removeClass(opened ? 'closed' : 'opened'); element.addClass(opened ? 'opened' : 'closed'); }; // Listens for the global click event broad-casted by the News service scope.$on('click', function() { if (element.find(News.clickTarget.tagName)[0] !== News.clickTarget) { scope.toggle(false); } }); // Init scope.toggle(); } } }]) 

Spero possa essere d’aiuto!

C’è una direttiva interessante chiamata angular-click-outside . Puoi usarlo nel tuo progetto. È super semplice da usare:

https://github.com/IamAdamJowett/angular-click-outside

Non ero totalmente soddisfatto delle risposte fornite, quindi ho fatto il mio. miglioramenti:

  • Aggiornamento più difensivo dell’ambito. Controllerà per vedere se un’applicazione / digest è già in corso
  • div si chiuderà anche quando l’utente preme la chiave di escape
  • gli eventi finestra non sono associati quando il div è chiuso (impedisce perdite)
  • gli eventi finestra non sono associati quando l’ambito viene distrutto (impedisce perdite)

    collegamento funzione (ambito, $ elemento, attributi, $ finestra) {

     var el = $element[0], $$window = angular.element($window); function onClick(event) { console.log('window clicked'); // might need to polyfill node.contains if (el.contains(event.target)) { console.log('click inside element'); return; } scope.isActive = !scope.isActive; if (!scope.$$phase) { scope.$apply(); } } function onKeyUp(event) { if (event.keyCode !== 27) { return; } console.log('escape pressed'); scope.isActive = false; if (!scope.$$phase) { scope.$apply(); } } function bindCloseHandler() { console.log('binding window click event'); $$window.on('click', onClick); $$window.on('keyup', onKeyUp); } function unbindCloseHandler() { console.log('unbinding window click event'); $$window.off('click', onClick); $$window.off('keyup', onKeyUp); } scope.$watch('isActive', function(newValue, oldValue) { if (newValue) { bindCloseHandler(); } else { unbindCloseHandler(); } }); // prevent leaks - destroy handlers when scope is destroyed scope.$on('$destroy', function() { unbindCloseHandler(); }); 

    }

Ottengo $window direttamente nella funzione di collegamento. Tuttavia, non è necessario farlo esattamente per ottenere $window .

 function directive($window) { return { restrict: 'AE', link: function(scope, $element, attributes) { link.call(null, scope, $element, attributes, $window); } }; } 

Usa angular-clic-esterno

Installazione:

 bower install angular-click-outside --save npm install @iamadamjowett/angular-click-outside yarn add @iamadamjowett/angular-click-outside 

Uso:

 angular.module('myApp', ['angular-click-outside']) //in your html  //And then in your controller $scope.closeThis = function () { console.log('closing'); }