7

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?

Chris Paterson
  • 1,129
  • 5
  • 21
  • 31

4 Answers4

1

Quick/easy way

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.

More 'Angular' way

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.

Community
  • 1
  • 1
anandthakker
  • 628
  • 6
  • 15
  • `click-off` looks interesting, but `$event.stopPropagation()` is IMHO a bad idea (which I'm unfortunately also using). Just try to use two such elements, open the first and click on the second. Now, both are open as the click gets stopped. – maaartinus Feb 20 '17 at 01:09
  • @anandthakker Your first fiddle link's broken. Can you update it please? – Barnee Feb 14 '18 at 09:21
1

In this solution:

Create a directive that binds to document click events.

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);
      })
    }
  }
});

Use it like so:

<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>
Community
  • 1
  • 1
Ilan Frumer
  • 32,059
  • 8
  • 70
  • 84
1

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);
      });

    }
  };
}]);
Pavlo Shandro
  • 808
  • 5
  • 12
-1
$window.addEventListener('click', function(e) {
    //your code
  });
David Buck
  • 3,752
  • 35
  • 31
  • 35
s.pathan
  • 1
  • 1
  • 4
    This question was asked 6 years ago. Can you please provide some context rather than just code? – David Buck Nov 20 '19 at 11:02
  • Hello David, if you want to set any variable or call any method when clicking anywhere in the browser window you can add $window.addEventListener of the top of your controller.whenever you click anywhere in browser your code will execute. and you can also get an event (like 'e') as an argument of this method. – s.pathan Dec 04 '19 at 05:13