projects/commons/src/lib/elements/dialog/components/dialog.component.ts
import { Observable, Subject } from 'rxjs';
import { animate, keyframes, style, transition, trigger } from '@angular/animations';
import {
Component, ComponentFactoryResolver, ElementRef, EventEmitter, HostListener, OnInit,
TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation
} from '@angular/core';
import { IDialogConfig } from '../interfaces';
interface ComponentType<T> {
new(...args: any[]): T;
}
@Component({
selector: 'cmn-dialog',
templateUrl: './dialog.component.html',
encapsulation: ViewEncapsulation.None,
animations: [
trigger('modalState', [
transition(
'void => active',
animate('200ms', keyframes([
style({ opacity: '0', top: '5%', offset: 0 }),
style({ opacity: '1', top: '0', offset: 1 })
]))
),
transition(
'active => inactive',
animate('200ms', keyframes([
style({ opacity: '1', offset: 0 }),
style({ opacity: '0', top: '5%', offset: 1 })
]))
)
])
]
})
export class DialogComponent<T> implements OnInit {
@ViewChild('header') public readonly headerEl: ElementRef;
@ViewChild('footer') public readonly footerEl: ElementRef;
@ViewChild('okButton') public readonly okButtonEl: ElementRef;
@ViewChild('cancelButton') public readonly cancelButtonEl: ElementRef;
@ViewChild('backdropButton') public readonly backdropButtonEl: ElementRef;
@ViewChild('componentSection', { read: ViewContainerRef }) public readonly componentSection: ViewContainerRef;
public open = false;
public componentInstance: T;
public hasComponent = false;
public config: IDialogConfig;
public ready = new EventEmitter<boolean>();
private fromOkButton = false;
private afterClosed$: Subject<any> = new Subject();
constructor(private readonly componentFactoryResolver: ComponentFactoryResolver) {}
public ngOnInit() {
this.open = true;
this.ready.next(true);
}
@HostListener('document:keydown.escape')
public keypress() {
this.backdropHandler();
}
public backdropHandler() {
if (this.config.hasBackdrop) {
this.dismiss(false);
}
}
public cancelHandler() {
this.actionHandler('cancelHandler');
}
public okHandler() {
this.actionHandler('okHandler', true);
}
public dismiss(fromOkButton: boolean) {
this.open = false;
this.fromOkButton = fromOkButton;
}
public animationDone(event: AnimationEvent) {
if ((event as any).fromState === 'active' && (event as any).toState === 'inactive') {
this.afterClosed$.next(this.fromOkButton);
this.afterClosed$.complete();
}
}
public afterClosed(): Observable<boolean> {
return this.afterClosed$.asObservable();
}
public _setComponent(componentOrTemplateRef: ComponentType<T> | TemplateRef<T>) {
if (componentOrTemplateRef instanceof TemplateRef) {
this.componentSection.createEmbeddedView(componentOrTemplateRef);
} else {
const factory = this.componentFactoryResolver.resolveComponentFactory(componentOrTemplateRef);
const componentRef = this.componentSection.createComponent(factory);
this.componentInstance = componentRef.instance as T;
}
this.hasComponent = true;
}
private actionHandler(action: 'okHandler' | 'cancelHandler', isDismiss: boolean = false) {
if (this.config[action]) {
this.config[action]();
} else {
this.dismiss(isDismiss);
}
}
}