Monday, January 20, 2020

Show dialog with angular material project

The below steps can be used to show dialog in an angular material project.

1. create angular project and add angular material package
ng new myapp
ng add @angular/material

2. add material design dialog module into app's module file app.module.ts

import {MatDialogModule} from '@angular/material';
@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule
  ],

3.Create dialog body component for displaying
First creating three files in the project as below
mydialog.component.ts
mydialog.componen.html
mydialog.component.css

mydialog.component.ts handles the data communication with dialog, the code is shown below
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import { ComponentOnInit } from '@angular/core';
@Component({
    selector: 'app-dialog',
    templateUrl: 'mydialog.component.html',
    styleUrls: ['mydialog.component.css']
})
export class MyDialogComponent implements OnInit {
    ngOnInit(): void {
        console.log('dialog opened')
    }
}

mydialog.component.html contains the dialog body
<h2 mat-dialog-title>My dialog title</h2>
<mat-dialog-content>


        <input matInput 
        placeholder="input description"
        >


</mat-dialog-content>


<mat-dialog-actions>
    <button class="mat-raised-button" (click)="close()">Close</button>
</mat-dialog-actions>

mydialog.component.css leaves as empty.

4. update app module file to import dialog component, and add it in entryComponents section
import {MatDialogModule} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';


@NgModule({
@NgModule({
  declarations: [
    AppComponent,
    MyDialogComponent
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents:[MyDialogComponent]
})

Test the project with "ng serve", it should show the default angular page.

5. remove default content from app.component.html and add a html button element to open the dialog
<button mat-button (click)="openDialog()">Open dialog</button>

Update app.component.ts to implement openDialog method as below
import { Component } from '@angular/core';
import {MatDialog, MatDialogConfig} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';

export class AppComponent {
  title = 'myapp';


  constructor(private dialog: MatDialog) {}


  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;


    this.dialog.open(MyDialogComponent, dialogConfig);
  }
}

Set disableClose to true so users can not close the dialog just by clicking outside of the dialog.

Save and run the project, when clicking the open dialog button, it should show the below dialog. Note the dialog cannot be closed now when clicking close button.

 6. close the dialog
Update mydialog.component.ts with a new close method
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import { Component, OnInit } from '@angular/core';

export class MyDialogComponent implements OnInit {
    constructor(private dialogRef: MatDialogRef<MyDialogComponent>) {}


    close() {
        this.dialogRef.close('input value from user');
    }
}
Test the project again, the dialog should be able to close.

7. passing data into dialog
MatDialogConfig object can be used to pass input data to dialog. Update mydialog.component.ts to add a new line to pass dialog title in dialogConfig.data object

  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;


    dialogConfig.data = {title: 'my material style'};
    this.dialog.open(MyDialogComponent, dialogConfig);
  }

Update mydialog component to receive input data:
import { Component, OnInit, Inject } from '@angular/core';

export class MyDialogComponent implements OnInit {
    diaTitle: string;
    constructor(private dialogRef: MatDialogRef<MyDialogComponent>,
                @Inject(MAT_DIALOG_DATA) data) {
          this.diaTitle = data.title;
        }
}

Update mydialog.component.html to use the diaTitle for the dialog title

<h2 mat-dialog-title>{{diaTitle}}</h2>

Test again, the title of  my material style" should show.

8. collecting user input from dialog
First update app module .ts file to include form module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {MatDialogModule} from '@angular/material';
import { MyDialogComponent } from './mydialog.component';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {FormsModule} from '@angular/forms';


@NgModule({
  declarations: [
    AppComponent,
    MyDialogComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule, 
    FormsModule
  ],

Then update app.component.ts to receive dialog output from afterClosed() method as below

  userInput: string;

  openDialog() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.autoFocus = true;
    dialogConfig.hasBackdrop = true;
    dialogConfig.disableClose = true;


    dialogConfig.data = {title: 'my material style'};


    const dialogRef = this.dialog.open(MyDialogComponent, dialogConfig);


    dialogRef.afterClosed().subscribe(result => {
      this.userInput = result;
    });
  }

Also update app.component.html to show the user output as below
<div>User input in dialog is: <span style="color: red;">{{userInput}}</span></div>
  
Then use ngModel two way bind to get input from dialog by update mydialog.component.html and mydialog.component.ts

mydialog.component.html
<h2 mat-dialog-title>{{diaTitle}}</h2>
<mat-dialog-content>
        <input matInput [(ngModel)] ="diaInput"
        placeholder="input description"
        >
</mat-dialog-content>
<mat-dialog-actions>
    <button class="mat-raised-button" (click)="close()">Close</button>
</mat-dialog-actions>

mydialog.component.ts
export class MyDialogComponent implements OnInit {
    diaTitle: string;
    diaInput: string;


    constructor(private dialogRef: MatDialogRef<MyDialogComponent>,
                @Inject(MAT_DIALOG_DATA) data) {
            this.diaTitle = data.title;
        }


    ngOnInit(): void {
        console.log('dialog opened')
    }


    close() {
        this.dialogRef.close(this.diaInput);
    }
}


Now testing the dialog, the user input will show after the dialog is closed.