Reputation:
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
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
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
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