Reputation: 3134
I have a multi-component sidebar toggle, app/button/sidebar are all in their own components, button/sidebar are children of app (or at least loaded within the app component, assume this is a child)
Still not quite up to speed on the cross-component communication aspect of Angular, I'm utilizing a service in this case.
What I'm after: if neither component button or sidebar are clicked (anything outside these two components)... collapse sidebar.
At current, I'm toggling a boolean state on a "visible" variable in a service to expand/collapse the nav.
I've tried all manner of methods with little success. What are some ways to accomplish this? Or at least somewhere I can read to get close and take it from there?
Code: https://stackblitz.com/edit/multi-component-communication
Upvotes: 2
Views: 1382
Reputation: 73791
Your current code works if the document:click
event handler toggles the visible
flag:
@HostListener("document:click", ["$event"])
onClick(event) {
this.visible = this._ref.nativeElement.contains(event.target);
}
To prevent the button click from reaching the document level, stop the event propagation:
<toggle-sidebar (click)="$event.stopPropagation()"></toggle-sidebar>
See this stackblitz for a demo.
Upvotes: 1
Reputation: 1463
You can handle clickOutSide
in both sidebar and button. And if both are clicked outside, close your sidebar. You can achieve the same by @Output/EventEmitter in both of your child components and listen to them in your app.component.ts
file.
So, to summarize:
clickOutSide
in sidebar, and emit the same to parent, i.e. app.component.ts
clickOutSide
in toggle button, and emit the same to parent, i.e. app.component.ts
app.component.ts
, handle above emits and perform checks :
I have edited your stackblitz here, considering the above scenarios.
Upvotes: 1
Reputation: 8478
You should be using a directive to listen to outside panel click:
import { Directive, ElementRef, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({
selector: '[clickOutside]'
})
export class ClickOutsideDirective {
@Output() clickOutside: EventEmitter<Event> = new EventEmitter<Event>();
constructor(private elementRef: ElementRef) { }
@HostListener('document:mousedown', ['$event'])
onDocumentClick(event: Event) {
if (!this.isClickInElement(event)) {
this.clickOutside.emit(event);
}
}
private isClickInElement(event: Event): boolean {
return this.elementRef.nativeElement.contains(event.target);
}
}
Now where you have the menu attach this directive and bind to it's output and call the method to collapse sidebar or do your action. Ex:
<ol (clickOutside)="collapseSideBar()">
Upvotes: 2