import { Component, ElementRef, OnDestroy, Input, Renderer2, ViewChild, ContentChild } from '@angular/core'; import { trigger, state, style, transition, animate, AnimationEvent } from '@angular/animations'; import { Header, Footer, DomHandler } from 'primeng/primeng'; @Component({ selector: 'p-dropdownPanel', templateUrl: './dropdown-panel.component.html', styleUrls: ['./dropdown-panel.component.scss'], animations: [ trigger('overlayAnimation', [ state('void', style({ // transform: 'translateY(5%)', transform: 'translate3d(0, 0, 0)', opacity: 0 })), state('visible', style({ // transform: 'translateY(0)', transform: 'translate3d(0, 0, 0)', opacity: 1 })), transition('void => visible', animate('225ms ease-in-out')), transition('visible => void', animate('195ms ease-in-out')) // transition('void => visible', animate('225ms ease-out')), // transition('visible => void', animate('195ms ease-in')) // transition('visible => void', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')), // transition('void => visible', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')) ]) ], providers: [DomHandler] }) export class DropdownPanelComponent implements OnDestroy { @Input() popup = true; @Input() style: any; @Input() styleClass: string; @Input() dropdownStyle: any; @Input() dropdownStyleClass: string; @Input() appendTo: any; @Input() autoZIndex = true; @Input() baseZIndex = 0; @ViewChild('container') containerViewChild: ElementRef; @ContentChild(Header) headerFacet; @ContentChild(Footer) footerFacet; container: HTMLDivElement; documentClickListener: any; documentResizeListener: any; preventDocumentDefault: boolean; target: any; visible = false; constructor( public el: ElementRef, public domHandler: DomHandler, public renderer: Renderer2 ) { } toggle(event) { if (this.visible) { this.hide(); } else { this.show(event); } this.preventDocumentDefault = true; } show(event) { this.target = event.currentTarget; this.visible = true; this.preventDocumentDefault = true; } onOverlayAnimationStart(event: AnimationEvent) { switch (event.toState) { case 'visible': if (this.popup) { this.container = event.element; this.moveOnTop(); this.appendOverlay(); this.domHandler.absolutePosition(this.container, this.target); this.bindDocumentClickListener(); this.bindDocumentResizeListener(); } break; case 'void': this.onOverlayHide(); break; } } appendOverlay() { if (this.appendTo) { if (this.appendTo === 'body') { document.body.appendChild(this.container); } else { this.domHandler.appendChild(this.container, this.appendTo); } } } restoreOverlayAppend() { if (this.container && this.appendTo) { this.el.nativeElement.appendChild(this.container); } } moveOnTop() { if (this.autoZIndex) { this.container.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex)); } } hide() { this.visible = false; } onWindowResize() { this.hide(); } bindDocumentClickListener() { if (!this.documentClickListener) { this.documentClickListener = this.renderer.listen('document', 'click', () => { if (!this.preventDocumentDefault) { this.hide(); } this.preventDocumentDefault = false; }); } } unbindDocumentClickListener() { if (this.documentClickListener) { this.documentClickListener(); this.documentClickListener = null; } } bindDocumentResizeListener() { this.documentResizeListener = this.onWindowResize.bind(this); window.addEventListener('resize', this.documentResizeListener); } unbindDocumentResizeListener() { if (this.documentResizeListener) { window.removeEventListener('resize', this.documentResizeListener); this.documentResizeListener = null; } } onOverlayHide() { this.unbindDocumentClickListener(); this.unbindDocumentResizeListener(); this.preventDocumentDefault = false; this.target = null; } ngOnDestroy() { if (this.popup) { this.restoreOverlayAppend(); this.onOverlayHide(); } } }