简体   繁体   中英

Angular - material modal with component wrapper and component as param

Im trying to create a dialog service which will show a wrapper component whose param is a component that should be displayed as content of the wrapper.

  open(component: any | TemplateRef<any>, params, viewMode: ViewMode = ViewMode.EDIT, className: string[] = ['as-dialog', 'as-dialog-large']): Observable<any> {

// Here some way to nest component in AsDialogWrapperComponent
// and then displaying AsDialogWrapperComponent with nested component as content
    this.dialogRef = this.matDialog.open(AsDialogWrapperComponent, {
      data: {
        params,
        viewMode
      },
      panelClass: className
    });
    return this.dialogRef.afterClosed();
  }

Wrapper code would be:

<div class="as-box as-vertical as-fh">
  <div class="as-dialog-header">
    <p class="as-dialog-header-text" mat-dialog-title #title></p>
  </div>
  <mat-dialog-content #content></mat-dialog-content>
</div>

So i am wondering if there is a way to nest component that comes as a param. I was trying to do something with componentFactoryResolver, but could not figure it out in the end.

The reason for all that is some views might be both modals and full screen views. So i could use a modal wrapper that would take title as param and some modal actions as either param or custom button bar.

Thanks for any tips.

Why not retrieve the data for your component from a service so you don't need to pass it through the MAT_DIALOG_DATA injection token and then you can use your component as either full screen or dialog without the need of a wrapper. Make sure you add it to the entryComponents list of your module though

Otherwise an answer for your question could be this: In your wrapper dialog "AsDialogWrapperComponent":

  private createComponent(config: DialogConfig) {
    this.destroyComponent();
    const factory: ComponentFactory<DialogBase<any>> = this.resolver.resolveComponentFactory(config.component);
    this.componentRef = this.container.createComponent(factory);
    (this.componentRef.instance as DialogBase<any>).data = config.data;
    (this.componentRef.instance as DialogBase<any>).close
      .pipe(take(1))
      .subscribe(this.closeDialog.bind(this));
    this.cdRef.detectChanges();
  }

  private destroyComponent() {
    this.container.clear();
    if (this.componentRef) {
      this.componentRef.destroy();
      this.componentRef = null;
    }
  }

where config is injected in the wrapper dialog:

constructor(@Inject(MAT_DIALOG_DATA) public data: DialogConfig) {}

and it looks like this:

export interface DialogConfig {
  component: { new(...args: any[]): any; };
  data: any;
}

and DialogBase can be either a class that your inner component extends:

import {
  EventEmitter,
  Output
} from '@angular/core';

export class DialogBase<T> {

  @Output() close: EventEmitter<void> = new EventEmitter();

  private _data: T;

  constructor() {
  }

  set data(data: T) {
    this._data = data;
  }

  get data(): T {
    return this._data;
  }
}

and T, the data interface expected by your component:

export class EditDialogComponent extends DialogBase<EditDialogData> {

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM