1

I'm using angular material to open dialogs. I have a lot of components that are getting openend in dialogs but as a matter of good separation of concerns I want to avoid baking in dialog behavior to the compoent. I have have a wrapper component call dashboard-dialog that has a ng-content area and provides some basic functionality and styling.

I would love to be able to do something like this like I could do with tsx/react;

const dialogComp = `<app-dashboard-dialog><app-create-user-form (create)="handleCreate()" cancel="handleCancel()"></app-create-user-form></app-dashboard-dialog>`
this.dialog.open(dialogComp, { ... });

Is there anything like this that will work with mat-dialog? How can I avoid making a dialog wrapped version of a component when we decide to open the component in a dialog?

Currently I am creating a new dialog component ex create-user-form-dialog.component.ts that has same template as my wished for dialogComp variable. and now opening this new dialog component this.dialog.open(CreateUserFormDialog, { ... });

The dialog component has the dialog ref and data injected.

@Component({
    selector: 'app-create-user-form-dialog',
    template: `
        <app-dashboard-dialog #dialog>
            <app-create-user-form
                [detail]="injected_detail"
                (create)="createUser($event)"
                (cancel)="cancel($event)"
            >
            </app-create-user-form>
        </app-dashboard-dialog>
    `,
    styleUrls: []
})

export class CreateUserFormDialogComponent {
    constructor(
        public dialogRef: MatDialogRef<CreateUserFormDialogComponent>,
        @Inject(MAT_DIALOG_DATA) public injected_detail: Info
    ) {}

So create-user-form.component.ts emits out the results of its buttons (save, cancel etc) and create-user-form-dialog.component.ts spits things back out via the dialogref.close method. Not sure how this complicates the situation and if ViewChild can still be used in some way.

Ken
  • 1,529
  • 12
  • 12
  • Maybe [this article](https://medium.com/@karsonbraaten/reducing-boilerplate-code-when-using-angular-material-dialog-d27f436072d5) is what you're looking for. – ionut-t May 13 '20 at 19:02
  • I did something like this for a project recently. You have to inject the component you want to display in the dialog, and then set up a service to relay the response back to the component that launched the dialog, because you can't use inputs or outputs. It's a lot of effort initially, but it is possible, and you do end up with just one dialog component. I'll see if I can do an example... – Matt Saunders May 13 '20 at 20:53
  • Any luck with the below @Ken? – Matt Saunders May 17 '20 at 21:38

1 Answers1

3

I've created a repo with a basic example of injecting a component (a form) into a reusable material dialog, which relays the user input back to the parent component that launched the dialog.

Here is a working demo on Stackblitz.

  • dialog-wrapper is the reusable dialog component
  • dialog-form is an example of a component being injected into dialog-wrapper, with the required services for data input / output
  • name (Alice) is an example of data being passed from the parent component to dialog-form
  • DialogFormResponseService updates a subject with name and the value from formControl faveFood when the form is submitted
  • The parent component subscribes to this service when dialog-wrapper is opened and closes the dialog when a response is received

The dialog wrapper itself is fairly simple; most of the heavy lifting is in the injected component and the parent component, but really it's just a case of adding two services to the component you're injecting into the dialog, to handle communication with the parent.

Matt Saunders
  • 3,538
  • 2
  • 22
  • 30