Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not sure how to hide a div when clicking OUTSIDE of the div

This is a follow-up question to this question: AngularJS input with focus kills ng-repeat filter of list

Basically my code is using AngularJS to pop-out a div (a drawer) on the right for filtering a list of things. Most times this is used the UI is blocked so clicking on that blocking div closes the drawer. But in some cases we don't block the UI and need to allow the user to click outside of the drawer to cancel the search or select something else on the page.

My initial thought was to attach a window.onclick handler when the drawer opens and if anything is clicked other than the drawer it should close the drawer. That's how I would do it in a pure JavaScript app. But in Angular it is being a bit more difficult.

Here is a jsfiddle with a sample that I based on @Yoshi's jsBin example: http://jsfiddle.net/tpeiffer/kDmn8/

The relevant piece of code from this sample is below. Basically if the user clicks outside of the drawer I invoke $scope.toggleSearch so that $scope.open is set back to false.

The code works, and even though the $scope.open goes from true to false it doesn't modify the DOM. I'm sure this has something to do with the lifecycle of events or perhaps when I modify $scope (since it is from a separate event) that it is a copy and not the original...

The ultimate goal on this will be for it to be a directive for ultimate reusability. If anyone can point me in the right direction to do that I would be grateful.

$scope.toggleSearch = function () {      $scope.open = !$scope.open;      if ($scope.open) {         $scope.$window.onclick = function (event) {             closeSearchWhenClickingElsewhere(event, $scope.toggleSearch);         };     } else {         $scope.$window.onclick = null;     } }; 

and

function closeSearchWhenClickingElsewhere(event, callbackOnClose) {      var clickedElement = event.target;     if (!clickedElement) return;      var elementClasses = clickedElement.classList;     var clickedOnSearchDrawer = elementClasses.contains('handle-right')          || elementClasses.contains('drawer-right')          || (clickedElement.parentElement !== null              && clickedElement.parentElement.classList.contains('drawer-right'));     if (!clickedOnSearchDrawer) {         callbackOnClose();     }  } 
like image 953
Thad Peiffer Avatar asked Jul 17 '13 17:07

Thad Peiffer


People also ask

How do I hide and show a div on click?

Projects In JavaScript & JQuery To show and hide div on mouse click using jQuery, use the toggle() method. On mouse click, the div is visible and on again clicking the div, it hides.

How do I hide a specific div?

To hide a div using JavaScript, get reference to the div element, and assign value of "none" to the element. style. display property.

How can you tell if someone is clicking outside a div?

To detect click outside div using JavaScript, we can check if e. target doesn't equal the inner element. document. getElementById("outer-container").


1 Answers

The drawer is not closing because the click event occurs outside the digest cycle and Angular doesn't know that $scope.open has changed. To fix it you can call $scope.$apply() after $scope.open is set to false, this will trigger the digest cycle.

$scope.toggleSearch = function () {     $scope.open = !$scope.open;     if ($scope.open) {         $scope.$window.onclick = function (event) {             closeSearchWhenClickingElsewhere(event, $scope.toggleSearch);         };     } else {         $scope.open = false;         $scope.$window.onclick = null;         $scope.$apply(); //--> trigger digest cycle and make angular aware.      } }; 

Here is your Fiddle.

I was also trying to create a directive for the search drawer, if it helps (it needs some fixes :)). Here is a JSBin.

like image 155
Bertrand Avatar answered Sep 23 '22 00:09

Bertrand