How to create a modal popup that is compatible with Angular 4 How to create a modal popup that is compatible with Angular 4 typescript typescript

How to create a modal popup that is compatible with Angular 4


The accepted answer adds a large dependency to swat a fly. Modal (and modeless) dialogs are largely the result of a CSS class or two. Try this "rename..." example:

1) Write the parent and child-modal as if the child wasn't modal at all, but just an inline form with *ngIf attached.

Parent HTML that uses <my-modal> child:

<div>    A div for {{name}}.    <button type="button" (click)="showModal()">Rename</button>    <my-modal *ngIf="showIt" [oldname]="name" (close)="closeModal($event)"></my-modal></div>

Parent class. The @Component decorator omitted for brevity. (The name property belongs to the parent class and would exist even if we didn't have a form to alter it.)

export class AppComponent {    name = "old name";    showIt = false;    showModal() {        this.showIt = true;    }    closeModal(newName: string) {        this.showIt = false;        if (newName) this.name = newName;    }}

Child to-be-modal component. @Component decorator and imports again omitted.

export class MyModalComponent {    @Input() oldname = "";    @Output() close = new EventEmitter<string>();    newname = "";    ngOnInit() {        // copy all inputs to avoid polluting them        this.newname = this.oldname;     }    ok() {        this.close.emit(this.newname);    }    cancel() {        this.close.emit(null);    }}

Child HTML before modal-izing it.

<div>    Rename {{oldname}}    <input type="text" (change)="newname = $event.target.value;" />    <button type="button" (click)="ok()">OK</button>    <button type="button" (click)="cancel()">Cancel</button></div>

2) Here's the CSS for child, but it can be placed in a global stylesheet for re-use throughout your app. It's a single class called modal and is intended for a <div> element.

.modal {    /* detach from rest of the document */    position: fixed;    /* center */    left: 50%;    top: 50%;    transform: translate(-50%, -50%);    /* ensure in front of rest of page -- increase as needed */    z-index: 1001;    /* visual illusion of being in front -- alter to taste */    box-shadow: rgba(0,0,0,0.4) 10px 10px 4px;    /* visual illusion of being a solid object -- alter to taste */    background-color: lightblue;    border: 5px solid darkblue;    /* visual preference of don't crowd the contents -- alter to taste */    padding: 10px;}

But the modal CSS class won't prevent interacting with the page underneath it. (So it technically creates a modeless dialog.) So we place an overlay underneath the modal to absorb and ignore mouse activity. overlay is also intended for a <div> element.

.overlay {    /* detach from document */    position: fixed;    /* ensure in front of rest of page except modal */    z-index: 1000;    /* fill screen to catch mice */    top: 0;    left: 0;    width: 9999px;    height: 9999px;    /* dim screen 20% -- alter to taste */    opacity: 0.2;    background-color: black;}

3) Use the modal and overlay in the child HTML.

<div class="modal">    Rename {{oldname}}    <input type="text" (change)="newname = $event.target.value;" />    <button type="button" (click)="ok()">OK</button>    <button type="button" (click)="cancel()">Cancel</button></div><div class="overlay"></div>

And that's it. Basically 2 CSS classes and you can make any component a modal. In fact you can show a component in-line or as a modal at run-time just by altering the existance of the CSS class with ngClass or [class.modal]="showAsModalBoolean".

You can alter this so the child controls the show/hide logic. Move the *ngIf, showIt, and show() function into the child. In the parent add @ViewChild(MyModalComponent) renameModal: MyModalComponent; and then the parent can imperatively call this.renameModal.show(this.name); and re-wire initialization and containing divs as needed.

The child-modal can return info to a parent's function as shown above, or the child's show() method could instead accept a callback or return a Promise, as per taste.

Two things to know:

this.renameModal.show(..); won't work if there's an *ngIf on <my-modal> because it won't exist to expose the function to begin with. *ngIf removes the whole component, show() function and all, so use [hidden] instead if you need this for some reason.

Modals-on-modals will have z-index issues since they all share the same z-index. This can be solved with [style.z-index]="calculatedValue" or similar.


Check Angular Material Dialogue, here is the Plunker

import {Component} from '@angular/core';import {MdDialog, MdDialogRef} from '@angular/material';@Component({  selector: 'dialog-result-example',  templateUrl: './dialog-result-example.html',})export class DialogResultExample {  selectedOption: string;  constructor(public dialog: MdDialog) {}  openDialog() {    let dialogRef = this.dialog.open(DialogResultExampleDialog);    dialogRef.afterClosed().subscribe(result => {      this.selectedOption = result;    });  }}@Component({  selector: 'dialog-result-example-dialog',  templateUrl: './dialog-result-example-dialog.html',})export class DialogResultExampleDialog {  constructor(public dialogRef: MdDialogRef<DialogResultExampleDialog>) {}}