Я разрабатываю проект angular 5. Моя домашняя страница состоит из многих компонентов. В navbarComponent у меня есть выпадающий список.
Когда раскрывающийся список открыт, при нажатии за его пределами я бы хотел, чтобы он закрывался автоматически.
Это мой код:
ngOnInit() {
this.showMenu = false;
}
toggle() {
this.showMenu = !this.showMenu;
}
<div *ngIf = "isConnect" class = " userStyle dropdown-toggle " (click) = "toggle()">
<ul class = "dropdown-menu subMenu" role = "menu" *ngIf = "showMenu">
<li (click) = "profile()" class = "subMenuItem"> PROFILE</li>
<li (click) = "administration()" class = "subMenuItem subMenuItem-last">ADMINISTRATION</li>
<li class = "subMenuItem subMenuItem-last"><button class = "btn blue-btn" (click) = "logout()" ><mat-icon mat-list-icon fontIcon = "icon-logout"></mat-icon>LOGOUT</button></li>
</ul>
</div>



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Добавьте TemplateRef-Id в ваше меню:
<ul #menuRef class = "dropdown-menu subMenu" role = "menu" *ngIf = "showMenu">
....
</ul>
Получите этот TemplateRef в коде:
@ViewChild('menuRef') menuRef: TemplateRef<any>;
Затем вам нужно зарегистрировать глобальное (на уровне документа) событие клика:
@HostListener('document:click', ['$event'])
hideMenu(event) {
if (!this.menuRef.nativeElement.Contains(event.target) {
if (this.showMenu) {
this.showMenu = false;
}
}
}
Если щелчок был за пределами раскрывающегося списка, вы устанавливаете showMenu=false, и ваше меню закрывается.
Но почему бы не использовать компонент для раскрывающегося списка? нг-выбрать делает все это автоматически.
Вот как я реализовал это в своем проекте. Сначала нам нужно привязать событие клика к окну в хуке ngOnInit.
ngOnInit() : void {
this.windowClickSubscription = Observable
.fromEvent(window, "click")
.subscribe(this.handleWindowClick)
}
Теперь всякий раз, когда происходит щелчок по окну, будет вызываться наш this.handleWindowClick, давайте добавим реализацию этого метода.
handleWindowClick(res: any) {
let target: any = res.target;
let threshold: number = 0;
while(target && target.className != 'grouped-control' && threshold <= 4) {
target = target.parentElement;
threshold++;
}
if (target && target.className != 'grouped-control') this.hasOptions = false;
}
Эта функция будет искать родителя цели события, пока не найдет grouped-control, который нам нужно закрыть, когда есть щелчок по окну, исключая этот элемент. Поэтому, если мы нашли этот элемент, мы больше ничего не делаем, мы закрываем его, используя флаг hasOptions.
Наконец, нам нужно отвязать это событие на ngDestroy.
ngOnDestroy(): void {
this.windowClickSubscription && this.windowClickSubscription.unsubscribe();
}
Теперь, конечно, вам нужно определить свойство this.windowClickSubscription в вашем компоненте и привязать ссылку компонента к функции handleWindowClick в вашем конструкторе.
Редактировать
Чтобы связать ссылку на конструктор, добавьте следующую строку в свой конструктор
constructor() {
this.handleWindowClick = this.handleWindowClick.bind(this);
}
Это позволит вам передать эту функцию в качестве обработчика обратного вызова, и она будет выполняться со ссылкой на ваш компонент.
Поскольку мы можем показать скрытый html с помощью *ngIf, я переключаю свой элемент управления, который мне нужно скрыть, используя флаг this. hasOptions.
Когда вы открываете раскрывающийся список, добавляется любой класс, например «открытый», с классом «раскрывающийся список», а когда вы закрываете раскрывающийся список, этот класс удаляется. Если щелкнуть за пределами области раскрывающегося списка, он закроется.
Я добился, используя приведенный ниже код
<div class = "drop-menu">
<a class = "dropdown-toggle" title = "Filter" (click) = "openDropdown()">
<span class = "fa fa-arrow"></span>
</a>
<ul class = "dropdown-menu subMenu" role = "menu" *ngIf = "showMenu">
<li (click) = "profile()" class = "subMenuItem"> PROFILE</li>
<li (click) = "administration()" class = "subMenuItem subMenuItem-last">ADMINISTRATION</li>
<li class = "subMenuItem subMenuItem-last"><button class = "btn blue-btn" (click) = "logout()" ><mat-icon mat-list-icon fontIcon = "icon-logout"></mat-icon>LOGOUT</button></li>
</ul>
</div>
Код для файла component.ts:
constructor(private renderer: Renderer2) { }
ngOnInit() {
const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
this.renderer.listen('document', 'click', (evt) => {
const eventPath = evt.path;
const hasClass = _.where(eventPath, { className: 'drop-menu' });
if (hasClass.length <= 0) {
this.renderer.removeClass(selectDOM, 'open');
}
});
}
openDropdown() {
const selectDOM = document.getElementsByClassName('dropdown-toggle')[0];
if (selectDOM.classList.contains('open')) {
this.renderer.removeClass(selectDOM, 'open');
} else {
this.renderer.addClass(selectDOM, 'open');
}
}
Что я делаю именно в конструкторе для handleWindowClick? И что я делаю в html-части?