user7426734
user7426734

Reputation:

Close the following dropdown when user click outside

I have a dropdown as follows, i want to close it when user click outside the dropdown.

<div  [class.open]="qtydropdownOpened">
  <button (click)="qtydropdownOpened = !qtydropdownOpened" type="button" 
         data-toggle="dropdown" aria-haspopup="true" [attr.aria-expanded]="qtydropdownOpened ? 'true': 'false' ">
   {{selectedqty}}<span class="caret margin-left-1x "></span>
 </button>
  <div class="dropdown-wrp dropdown-menu">
  <ul class="default-dropdown">
      <li *ngFor="let quantity of quantities">
       <a (click)="qtydropdownOpened = !qtydropdownOpened;setQuantity(quantity)">{{quantity  }}</a>
       </li>
   </ul>
  </div>
 </div>

i have tried with Angular2 Close dropdown on click outside, is there an easiest way? method but it does not seem to work.

EXPECTED BEHAVIOUR: The dropdown should be closed.

ACTUAL BEHAVIOUR: It remains opened.

Upvotes: 1

Views: 4124

Answers (3)

Shannon
Shannon

Reputation: 914

I had the same issue when I was making a drop-down menu and a confirmation dialog I wanted to dismiss them when clicking outside.

My final implementation works perfectly but requires some css3 animations and styling.

NOTE: i have not tested the below code, there may be some syntax problems that need to be ironed out, also the obvious adjustments for your own project!

What i did:

I made a separate fixed div with height 100%, width 100% and transform:scale(0), this is essentially the background, you can style it with background-color: rgba(0, 0, 0, 0.466); to make obvious the menu is open and the background is click-to-close. The menu gets a z-index higher than everything else, then the background div gets a z-index lower than the menu but also higher than everything else. Then the background has a click event that close the drop-down.

Here it is with your html code.

<div class="dropdownbackground" [ngClass]="{showbackground: qtydropdownOpened}" (click)="qtydropdownOpened = !qtydropdownOpened"><div>
<div class="zindex" [class.open]="qtydropdownOpened">
  <button (click)="qtydropdownOpened = !qtydropdownOpened" type="button" 
         data-toggle="dropdown" aria-haspopup="true" [attr.aria-expanded]="qtydropdownOpened ? 'true': 'false' ">
   {{selectedqty}}<span class="caret margin-left-1x "></span>
 </button>
  <div class="dropdown-wrp dropdown-menu">
  <ul class="default-dropdown">
      <li *ngFor="let quantity of quantities">
       <a (click)="qtydropdownOpened = !qtydropdownOpened;setQuantity(quantity)">{{quantity  }}</a>
       </li>
   </ul>
  </div>
 </div>

Here is the css3 which needs some simple animations.

/* make sure the menu/drop-down is in front of the background */
.zindex{
    z-index: 3;
}

/* make background fill the whole page but sit behind the drop-down, then
scale it to 0 so its essentially gone from the page */
.dropdownbackground{
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 2;
    transform: scale(0);
    opacity: 0;
    background-color: rgba(0, 0, 0, 0.466);
}

/* this is the class we add in the template when the drop down is opened
it has the animation rules set these how you like */
.showbackground{
    animation: showBackGround 0.4s 1 forwards; 

}

/* this animates the background to fill the page
if you don't want any thing visual you could use a transition instead */
@keyframes showBackGround {
    1%{
        transform: scale(1);
        opacity: 0;
    }
    100% {
        transform: scale(1);
        opacity: 1;
    }
}

If you aren't after anything visual you can just use a transition like this

.dropdownbackground{
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 2;
    transform: scale(0);
    opacity: 0;
    transition all 0.1s;
}

.dropdownbackground.showbackground{
     transform: scale(1);
}

Upvotes: 0

Jorawar Singh
Jorawar Singh

Reputation: 7621

<div>
  <button  (click)="myFunction()" type="button" 
         data-toggle="dropdown" aria-haspopup="true" [attr.aria-expanded]="qtydropdownOpened ? 'true': 'false' ">
   {{selectedqty}}<span class="caret margin-left-1x "></span>
 </button>
  <div class="dropdown-wrp dropdown-menu" #myDropdown>
  <ul class="default-dropdown">
      <li *ngFor="let quantity of quantities">
       <a (click)="qtydropdownOpened = !qtydropdownOpened;setQuantity(quantity)">{{quantity  }}</a>
       </li>
   </ul>
  </div>
 </div>

In your Component

@Component({
        templateUrl: 'header.html'
        host: {
            '(document:click)': 'onClick($event)'
        }
})
export class DropDownComponent{
@ViewChild('myDropdown') myDropdown: ElementRef;
    public myFunction() {
      this.myDropdown.nativeElement.classList.toggle("show")
    }
 // Close the dropdown if the user clicks outside of it
onClick(event) {
    if (!event.target.matches('.dropbtn')) {

        var dropdowns = this.myDropdown.nativeElement;
        if (dropdowns.classList.contains('show')) {
            dropdowns.classList.remove('show');
        }
    }
 }
}

Upvotes: 0

Merih Taze
Merih Taze

Reputation: 41

I think you have two options. First one is to make the div content editable(Or use another element that has blur event) and add a listener to blur event to hide the drowdown. Blur will be triggered when the element loses focus like clicking outside etc.

Or you can add a window listener to your component and hide it when there's a click outside of the dropdown like:

@Component({
  selector: 'mySelector',
  template : 'YourTemplatehere',
  host: {'(window:mouseup)': 'handleMouseUp($event)'},
})

export class MyClass {
  handleMouseUp(e: MouseEvent) {
    // Your code to handle the hiding logic. I think in your case its;
    this.qtydropdownOpened = !this.qtydropdownOpened;
  }
}

Upvotes: 1

Related Questions