Skip to content

Instantly share code, notes, and snippets.

@l0co
Last active March 5, 2020 15:27
Show Gist options
  • Save l0co/0e2c9cb217ae86ba3e1ef9e1f87653c2 to your computer and use it in GitHub Desktop.
Save l0co/0e2c9cb217ae86ba3e1ef9e1f87653c2 to your computer and use it in GitHub Desktop.
Angular material dialog component.
<div class="mat-card-dialog">
<h2 mat-dialog-title class="mat-card-dialog-title" *ngIf="title">{{title}}</h2>
<mat-icon mat-dialog-close class="mat-card-dialog-close pointer">close</mat-icon>
<ng-content></ng-content>
</div>
import {AfterViewInit, Component, ContentChild, Input, OnInit} from '@angular/core';
import {CardDialogService} from "../services/card-dialog.service";
/**
* Angular material dialog component.
*
* ## Usage in template
*
* Put your component into `<app-card-dialog>` component, marking it with `#dialogComponent`.
*
* ```html
* <ng-template #myTemplate let-data> <!-- Use own ID and let-data if you want use custom data -->
* <app-card-dialog> <!-- This component is required as a top component -->
* <app-my-component <!-- This component is whatever one -->
* [myattr1]="data.attr1" <!-- You can set attributes using custom data (requires: let-data) -->
* [myattr2]="attr2" <!-- Or in a standard way from the parent component -->
* #dialogComponent> <!-- #dialogComponent is required to be set here (!) -->
* </app-my-component>
* </app-card-dialog>
* </ng-template>
* ```
*
* ## Usage in (parent) component
*
* ```typescript
* class MyComponent {
*
* @ViewChild('myTemplate') myTemplate: TemplateRef<any>;
* attr2: string = 'value of attribute 2';
*
* constructor(private cardDialog: CardDialogService) {}
*
* openDialog() {
* this.cardDialog.open<MyComponent>(this.myTemplate, {attr1: 'value of attribute 1'}).subscribe(component => {
* // here you have access to MyComponent instance as well (what's almost impossible for angular when it's inside ng-template)
* });
* }
*
* closeDialog() {
* this.cardDialog.close();
* }
*
* }
* ```
*/
@Component({
selector: 'app-card-dialog',
templateUrl: './card-dialog.component.html',
styleUrls: ['./card-dialog.component.scss']
})
export class CardDialogComponent<C = any> implements OnInit, AfterViewInit {
@Input('title') title?: string;
@ContentChild('dialogComponent') component: C;
constructor(
private cardDialogService: CardDialogService,
) { }
ngOnInit(): void {
}
ngAfterViewInit(): void {
this.cardDialogService.onComponentReady(this.component);
}
}
import {Injectable, TemplateRef} from '@angular/core';
import {MatDialog, MatDialogConfig} from "@angular/material/dialog";
import {MatDialogRef} from "@angular/material/dialog/dialog-ref";
import {Loggable} from "../../../classes/loggable.class";
import {NGXLogger} from "ngx-logger";
import {Observable, Subject} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class CardDialogService extends Loggable {
protected dialogs: {dialog: MatDialogRef<any>, component: Subject<any>, current?: any}[] = [];
constructor(
log: NGXLogger,
private matDialog: MatDialog,
) {
super(log);
}
open<C>(dialogTemplate: TemplateRef<any>, data?: any, config?: MatDialogConfig): Observable<C> {
this.log.debug('Opening dialog', this.dialogs.length);
let single = new Subject<C>();
let dialog = {
dialog: this.matDialog.open(dialogTemplate, Object.assign({
panelClass: 'mat-card-panel-container',
maxHeight: '90vh',
data,
},
config || {})
),
component: single
};
dialog.dialog.afterClosed().subscribe(it => {
this.onClose();
});
this.dialogs.push(dialog);
return single;
}
close() {
this.dialogs[this.dialogs.length-1].dialog.close();
}
protected onClose() {
this.dialogs.pop();
this.log.debug('Closing dialog', this.dialogs.length);
}
onComponentReady(component: any) {
this.log.debug('Registering component for current dialog:', component.constructor.name);
this.dialogs[this.dialogs.length-1].component.next(component);
this.dialogs[this.dialogs.length-1].component.complete();
this.dialogs[this.dialogs.length-1].current = component;
}
get currentComponent(): any {
return this.dialogs[this.dialogs.length-1]?.current;
}
get currentDialogRef(): MatDialogRef<any> {
return this.dialogs[this.dialogs.length-1]?.dialog;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment