Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to be able to create a popup window which will load a certain Angular 4 component of mine when a radio button is selected.

It seems that the methods listed in the answers to this question are only compatible with Angular 2.

I am not sure where to begin and would appreciate any help!

like image 736
Luca Guarro Avatar asked Apr 21 '17 03:04

Luca Guarro


People also ask

What is modal popup in angular?

Modals are small pop-up windows which are really handy when you want to display to the user extra content, configuration or consent request. To use modals, just follow the steps below. 1. Import the required ViewChild and Modal directives in app.component.ts.

How do I create a popup in TypeScript?

Approach: Import NgbModal module in the TypeScript file of the corresponding component, and then we have to write code for the popup model by using the above module in the HTML file of the corresponding component. Now, we have to use ng-template to construct the model which will create a popup.


1 Answers

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.

like image 159
Ron Newcomb Avatar answered Sep 18 '22 18:09

Ron Newcomb