11

I am trying to add an Angular Material dialog box(just a title and yes/no) that gets called before my web service executes. The thing is that I do not want to create the dialogs HTML in a separate component. I need the dialogs HTML to be in the same file as my existing code. The dialog needs to open when I click on the callAPI button. Here is my existing component code

<mat-tab-group>
    <mat-tab label="Tab 1">
       <button mat-flat-button color="warn" (click)="callAPI()">Open Dialog</button>
    </mat-tab>
    <mat-tab label="Tab 2">
    </mat-tab>
</mat-tab-group>
callAPI() {
    this.http.get<any>('https://example.com/api').subscribe(data => {
      this.data = data;
      this.loading = false;
    },
    err => {
        this.loading = false;
    });
}
Edric
  • 24,639
  • 13
  • 81
  • 91
skydev
  • 1,867
  • 9
  • 37
  • 71

2 Answers2

16

Update: I was not correct in my assumptions that the TemplateRef's type parameter was the component reference - in fact, it's actually the "data-binding context of the embedded view", as shown in the documentation for the TemplateRef#createEmbeddedView method:

abstract createEmbeddedView(context: C): EmbeddedViewRef<C>

Description:

Instantiates an embedded view based on this template, and attaches it to the view container.

Parameters:

context (type: C) The data-binding context of the embedded view, as declared in the usage.


You can pass in a template reference to MatDialog#open:

<ng-template #callAPIDialog>
    <h2 matDialogTitle>Hello dialog!</h2>
    <mat-dialog-actions align="end">
        <button mat-button matDialogClose="no">No</button>
        <button mat-button matDialogClose="yes">Yes</button>
    </mat-dialog-actions>
</ng-template>
import { TemplateRef, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material';

@Component({ /* */ })
export class MyComponent {

    @ViewChild('callAPIDialog') callAPIDialog: TemplateRef<any>;

    constructor(private dialog: MatDialog) { }

    callAPI() {
        let dialogRef = this.dialog.open(this.callAPIDialog);
        dialogRef.afterClosed().subscribe(result => {
            // Note: If the user clicks outside the dialog or presses the escape key, there'll be no result
            if (result !== undefined) {
                if (result === 'yes') {
                    // TODO: Replace the following line with your code.
                    console.log('User clicked yes.');
                } else if (result === 'no') {
                    // TODO: Replace the following line with your code.
                    console.log('User clicked no.');
                }
            }
        })
    }
Edric
  • 24,639
  • 13
  • 81
  • 91
  • 1
    Hi @Edric , this code is working.... super.. Thanks !!!. Only code need to be add ```@ViewChild('callAPIDialog') callAPIDialog: TemplateRef;``` – Sanjay Tiwari Jun 21 '19 at 11:25
  • 1
    Yes agree with @SanjayTiwari – NiallMitch14 Dec 13 '19 at 12:10
  • 1
    @SanjayTiwari I've edited the answer to include your comment. – Edric Dec 13 '19 at 12:15
  • 1
    As of recent, this now needs to be : `@ViewChild('callAPIDialog', {static: false}) callAPIDialog: TemplateRef;` – Jeremy Feb 24 '20 at 20:58
  • @JeremyLucas There's no need to specify the `static` field (if you're setting it to `false`) from Angular v9 and up as it's now defaulted to `false`: https://angular.io/guide/static-query-migration – Edric Feb 25 '20 at 05:27
  • @Edric Thanks, VsCode was giving me errors (would still run, but had type errors) so I thought I would add the comment `ERROR in src/app/features.component.ts(35,4): error TS2554: Expected 2 arguments, but got 1.` https://imgur.com/ZA0fb00 – Jeremy Feb 25 '20 at 16:13
  • hi, can someone answer this question? thanks https://stackoverflow.com/questions/62807800/angular-material-popup-windows-allow-windows-to-go-between-front-and-back –  Jul 09 '20 at 05:09
3

Initially I tried what Edric suggested and the dialog opened perfectly but I was kinda lost when I wanted to close it from the component after some processing and not just with the template directive matDialogClose. So I conducted a search on this topic and it took me a while to join all the pieces and figure out that the template reference is something different than the dialog reference of that piece of template. So hands on work putting it all together...

<!-- Edit Company -->
<ng-template #editCompanyModal>
  <div class="mat-dialog-header border-bottom">
    <h2 mat-dialog-title class="mb-0">Edit Company</h2>
    <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="12px">
      <button mat-icon-button matDialogClose tabindex="-1">
        <mat-icon aria-label="Close dialog">close</mat-icon>
      </button>
    </div>
  </div>
  <form #editCompanyForm="ngForm" role="form" novalidate name="editCompanyForm"
          (ngSubmit)="editCompanyFormSubmit(editCompanyForm)">
    <mat-dialog-content>
      <fieldset>
        ...
      </fieldset>
    </mat-dialog-content>
    <mat-dialog-actions class="border-top">
      <button type="button" mat-button matDialogClose>Cancel</button>
      <button type="submit" mat-raised-button color="accent"
              [disabled]="!editCompanyForm.valid">Save changes</button>
    </mat-dialog-actions>
  </form>
</ng-template>
@Component({
  ...
})
export class AccountCompanyComponent {

  @ViewChild('editCompanyModal') editCompanyModal: TemplateRef<any>;
  private editCompanyDialogRef: MatDialogRef<TemplateRef<any>>;

  constructor(public dialog: MatDialog) {}

  // Dialog handling

  openCompanyDetailsDialog(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.restoreFocus = false;
    dialogConfig.autoFocus = false;
    dialogConfig.role = 'dialog';

    this.editCompanyDialogRef = this.dialog.open(this.editCompanyModal, dialogConfig);

    this.editCompanyDialogRef.afterClosed().subscribe(result => {
      consoleOut('The dialog was closed...');
    });
  }

  closeCompanyDetailsDialog() {
    this.editCompanyDialogRef.close();
  }

  editCompanyFormSubmit(form: NgForm) {
    if (!form.valid) {
      return false;
    }
    // Save company data
  }
Sparker73
  • 303
  • 2
  • 10