I have a dropdown menu on my site that is controlled by ng-show
. When the user clicks on a button they see the dropdown. When they click again, the dropdown is hidden:
<div class="button" ng-click="show = !show">Click Me</div>
<div ng-show="show" ng-init="show = false">
<div>You can see me now!</div>
</div>
This works fine. But, what I want is for show
to be set to false if the user clicks anywhere in the window that is not the div with class "button". How can I achieve this?
The quickest/easiest way to do this would be to put your cancellation code (ng-click="show=false"
) on the body
element, and then add $event.stopPropagation()
to the existing ng-click. This way, any time you click on the button, since the click event is prevented from propagating upward, the cancellation code wouldn't fire. Clicking anywhere else, though, would fire the ng-click
on the body
, so that the cancellation code will run. Here's a fiddle that does this.
I think a slightly "better" or "more angular" way to do get the same result would be to create a new click-off
directive that can sit alongside ng-click. The new directive could (a) register another click handler on the target element which would stop propagation, and (b) register a click handler on the body
element to fire whatever cancellation code you need. Here's a fiddle for that approach.
HTML:
<div customDropdown>
<h4>Click here to see dropdown</h4>
<ul ng-show="dropdownVisible">
<li ng-click="doSomething()">Item #1</li>
<li ng-click="doSomething()">Item #2</li>
<li ng-click="doSomething()">Item #3</li>
</ul>
</div>
Simple directive:
app.directive('customDropdown', ['$document', function($document) {
return {
restrict: 'A',
link: function(scope, el) {
// Switch dropdown visibility by clicking on 'target' element
el.on('click', function(event) {
event.preventDefault();
scope.dropdownVisible = !scope.dropdownVisible;
});
// Hide dropdown if clicked somewhere 'outside'
$document.on('click', function(event) {
scope.dropdownVisible = false;
return $document.off('click', event);
});
}
};
}]);
app.directive('clickOnlyHere',function(){
return {
scope: {
clickOnlyHere: "="
},
link: function(scope, element, attrs) {
var clickHandler = function(event){
// we need to check if the click is within our element ( or its decedents).
var inside = (element[0] === event.target) ||
$(event.target).parents().index(element) !== -1;
var show = inside ? !scope.clickOnlyHere : false;
scope.$apply(function() {
scope.clickOnlyHere = show;
});
}
$(document).on('click', clickHandler);
// must remove the click handler after our scope is destroyed.
scope.$on('$destroy',function(){
$(document).off('click', clickHandler);
})
}
}
});
<div class="button" click-only-here="show">Click Me</div>
<div ng-show="show" ng-init="show = false">
<div>You can see me now!</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With