Я пытаюсь создать раскрывающийся список многоселевых экранов с флажком и фильтром. Я пытаюсь скрыть список, когда я нажимаю на него, но не мог понять, как это сделать. Цените свою помощь.
Выпадающая директива AngularJS скрыть при нажатии
Ответ 1
Остерегайтесь, ваше решение (предоставленный Plunker в вопросе) не закрывает всплывающие окна других ящиков при открытии второго всплывающего окна (на странице с несколькими выборами).
Нажав на поле, чтобы открыть новое всплывающее окно, событие клика всегда будет остановлено. Событие никогда не достигнет какого-либо другого открытого всплывающего окна (чтобы закрыть их).
Я решил это, удалив строку event.stopPropagation();
и сопоставив все дочерние элементы всплывающего окна.
Всплывающее окно будет закрыто только в том случае, если элемент событий не соответствует дочерним элементам всплывающего окна.
Я изменил код директивы на следующее:
select.html(директивный код)
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;
});
});
}
Я разблокировал ваш плункер и применил изменения:
Plunker: скрыть всплывающее окно на клике снаружи
Скриншот:
Ответ 2
Это старый пост, но в случае, если это помогает кому-либо, это рабочий пример щелчка снаружи, который не полагается ни на что, кроме 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);
});
}
});
}
}
});
Ответ 3
OK Мне пришлось вызвать $apply(), поскольку событие происходит вне мира angular (согласно документу).
element.bind('click', function(event) {
event.stopPropagation();
});
$document.bind('click', function(){
scope.isVisible = false;
scope.$apply();
});
Ответ 4
Я понял это, слушая глобальное событие клика, например:
.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);
});
}
}])
Затем само событие транслируется через службу новостей
angular.factory('News', ['$rootScope', function($rootScope) {
var news = {};
news.setClick = function( target ) {
this.clickTarget = target;
$rootScope.$broadcast('click');
};
}]);
Вы можете слушать трансляцию в любом месте, где вам нужно. Вот примерная директива:
.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();
}
}
}])
Надеюсь, это поможет!
Ответ 5
Существует крутая директива, называемая angular-click-outside
. Вы можете использовать его в своем проекте. Он очень прост в использовании:
Ответ 6
Я не был полностью доволен ответами, поэтому я сделал свой собственный. Улучшения:
- Более защитное обновление области. Будет проверять, будет ли выполняться приложение/дайджест.
- div также закрывается, когда пользователь нажимает клавишу
- события окна не связаны, когда div закрыт (предотвращает утечки)
-
события окна не привязаны при уничтожении области (предотвращает утечки)
функция link (scope, $element, attributes, $window) {
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(); });
}
Я получаю $window
непосредственно в функцию связи. Однако вам не нужно делать это точно, чтобы получить $window
.
function directive($window) {
return {
restrict: 'AE',
link: function(scope, $element, attributes) {
link.call(null, scope, $element, attributes, $window);
}
};
}