import { ComponentType , Overlay , OverlayConfig , OverlayRef } from '@angular/cdk/overlay' ; import { ComponentPortal , PortalInjector } from '@angular/cdk/portal' ; import { Location } from '@angular/common' ; import { ComponentRef , Inject , Injectable , Injector , Optional , SkipSelf } from '@angular/core' ; import { defer , Observable , Subject } from 'rxjs' ; import { startWith } from 'rxjs/operators' ; import { DialogConfig } from './dialog-config' ; import { DialogContainerComponent } from './dialog-container.component' ; import { DIALOG_DATA , DIALOG_SCROLL_STRATEGY } from './dialog-injectors' ; import { DialogRef } from './dialog-ref' ; @ Injectable ( ) export class Dialog { get _afterAllClosed ( ) : Observable < void > { return this . parentDialog ? this . parentDialog . afterAllClosed : this . _afterAllClosedBase ; } _afterOpened : Subject < DialogRef < any > > = new Subject ( ) ; get afterOpened ( ) : Subject < DialogRef < any > > { return this . parentDialog ? this . parentDialog . afterOpened : this . _afterOpened ; } _openDialogs : DialogRef < any > [ ] = [ ] ; get openDialogs ( ) : DialogRef < any > [ ] { return this . parentDialog ? this . parentDialog . openDialogs : this . _openDialogs ; } afterAllClosed : Observable < void > = defer < void > ( ( ) => this . openDialogs . length ? this . _afterAllClosed : this . _afterAllClosed . pipe ( startWith ( undefined ) ) ) ; private _afterAllClosedBase = new Subject < void > ( ) ; constructor ( private overlay , private injector , @ Inject ( DIALOG_SCROLL_STRATEGY ) private scrollStrategy , @ Optional ( ) @ SkipSelf ( ) private parentDialog , @ Optional ( ) location ) { if ( ! parentDialog && location ) { location . subscribe ( ( ) => this . closeAll ( ) ) ; } } getById ( id ) { return this . _openDialogs . find ( ref => ref . id === id ) ; } closeAll ( ) { this . openDialogs . forEach ( ref => ref . close ( ) ) ; } param component param config open < T , D = any , R = any > ( component , config ? ) { config = this . _applyConfigDefaults ( config ) ; if ( config . id && this . getById ( config . id ) ) { throw Error ( `Dialog with id "${ config . id }" exists already. The dialog id must be unique.` ) ; } const overlayRef = this . createOverlay ( config ) ; const dialogContainer = this . attachDialogContainer ( overlayRef , config ) ; const dialogRef = this . attachDialogContentForComponent < T > ( component , dialogContainer , overlayRef , config ) ; this . registerDialogRef ( dialogRef ) ; return dialogRef ; } param config returns protected createOverlay ( config ) { const overlayConfig = new OverlayConfig ( { positionStrategy : this . overlay . position ( ) . global ( ) , scrollStrategy : this . scrollStrategy ( ) , backdropClass : [ 'DialogBackdrop' ] , hasBackdrop : config . hasBackdrop , minWidth : config . minWidth , minHeight : config . minHeight , maxWidth : config . maxWidth , maxHeight : config . maxHeight , width : config . width , height : config . height , } ) ; return this . overlay . create ( overlayConfig ) ; } param overlay param config protected attachDialogContainer ( overlay , config ) { const injector = new PortalInjector ( this . injector , new WeakMap ( [ [ DialogConfig , config ] , ] ) ) ; const containerPortal = new ComponentPortal ( DialogContainerComponent , undefined , injector ) ; const containerRef = overlay . attach ( containerPortal ) ; containerRef . instance . config = config ; return containerRef . instance ; } param component param dialogContainer param overlayRef param config protected attachDialogContentForComponent < T > ( component , dialogContainer , overlayRef , config ) { const dialogRef = new DialogRef < T > ( overlayRef , dialogContainer , config . id ) as DialogRef < T > ; const injector = this . createInjector < T > ( config , dialogRef , dialogContainer ) ; const contentRef = dialogContainer . attachComponentPortal ( new ComponentPortal ( component , undefined , injector ) ) ; dialogRef . componentInstance = contentRef . instance ; dialogRef . updateSize ( { width : config . width , height : config . height } ) . updatePosition ( config . position ) ; return dialogRef ; } param dialogRef private registerDialogRef ( dialogRef ) { this . openDialogs . push ( dialogRef ) ; const dialogOpenSub = dialogRef . afterOpened ( ) . subscribe ( ( ) => { this . afterOpened . next ( dialogRef ) ; dialogOpenSub . unsubscribe ( ) ; } ) ; const dialogCloseSub = dialogRef . afterClosed ( ) . subscribe ( ( ) => { const dialogIndex = this . _openDialogs . indexOf ( dialogRef ) ; if ( dialogIndex > - 1 ) { this . _openDialogs . splice ( dialogIndex , 1 ) ; } if ( ! this . _openDialogs . length ) { this . _afterAllClosedBase . next ( ) ; dialogCloseSub . unsubscribe ( ) ; } } ) ; } param config param dialogRef param dialogContainer private createInjector < T > ( config , dialogRef , dialogContainer ) { const injectionTokens = new WeakMap < any , any > ( [ [ DialogRef , dialogRef ] , [ DialogContainerComponent , dialogContainer ] , [ DIALOG_DATA , config . data ] , ] ) ; return new PortalInjector ( this . injector , injectionTokens ) ; } private _applyConfigDefaults ( config ? ) { return { ... new DialogConfig ( ) , ... config } ; } }