简体   繁体   中英

How to use code to open a modal in Angular 2?

Usually we use data-target="#myModal" in the <button> to open a modal. Right now I need use codes to control when to open the modal.

If I use [hidden] or *ngIf to show it, I need remove class="modal fade" , otherwise, the modal will never show. Like this:

<div [hidden]="hideModal" id="myModal">

However, in this case, after removing class="modal fade" , the modal won't fade in and has no shade in the background. And what's worse, it will show at the screen bottom instead of screen center.

Is there a way to keep class="modal fade" and use code to open it?

<button type="button" data-toggle="modal" data-target="#myModal">Open Modal</button>

<div id="myModal" class="modal fade">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body">
        <p>Some text in the modal.</p>
      </div>
    </div>
  </div>
</div>

This is one way I found. You can add a hidden button:

<button id="openModalButton" [hidden]="true" data-toggle="modal" data-target="#myModal">Open Modal</button>

Then use the code to "click" the button to open the modal:

document.getElementById("openModalButton").click();

This way can keep the bootstrap style of the modal and the fade in animation.

Include jQuery as usual inside script tags in index.html.

After all the imports but before declaring @Component, add:

declare var $: any;

Now you are free to use jQuery anywhere in your Angular 2 TypeScript code:

$("#myModal").modal('show');

Reference: https://stackoverflow.com/a/38246116/2473022

Easy way to achieve this in angular 2 or 4 (Assuming that you are using bootstrap 4 )

Component.html

 <button type="button" (click)="openModel()">Open Modal</button> <div #myModel class="modal fade"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title ">Title</h5> <button type="button" class="close" (click)="closeModel()"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"> <p>Some text in the modal.</p> </div> </div> </div> </div>

Component.ts

import {Component, OnInit, ViewChild} from '@angular/core';

@ViewChild('myModal') myModal;

openModel() {
  this.myModal.nativeElement.className = 'modal fade show';
}
closeModel() {
   this.myModal.nativeElement.className = 'modal hide';
}

The below answer is in reference to the latest ng-bootstrap

Install

npm install --save @ng-bootstrap/ng-bootstrap

app.module.ts

import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...

    NgbModule

  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Component Controller

import { TemplateRef, ViewChild } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-app-registration',
  templateUrl: './app-registration.component.html',
  styleUrls: ['./app-registration.component.css']
})

export class AppRegistrationComponent implements OnInit {

  @ViewChild('editModal') editModal : TemplateRef<any>; // Note: TemplateRef

  constructor(private modalService: NgbModal) { }

  openModal(){
    this.modalService.open(this.editModal);
  }

}

Component HTML

<ng-template #editModal let-modal>

<div class="modal-header">
  <h4 class="modal-title" id="modal-basic-title">Edit Form</h4>
  <button type="button" class="close" aria-label="Close" (click)="modal.dismiss()">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

<div class="modal-body">
  
  <form>
    <div class="form-group">
      <label for="dateOfBirth">Date of birth</label>
      <div class="input-group">
        <input id="dateOfBirth" class="form-control" placeholder="yyyy-mm-dd" name="dp" ngbDatepicker #dp="ngbDatepicker">
        <div class="input-group-append">
          <button class="btn btn-outline-secondary calendar" (click)="dp.toggle()" type="button"></button>
        </div>
      </div>
    </div>
  </form>

</div>

<div class="modal-footer">
  <button type="button" class="btn btn-outline-dark" (click)="modal.close()">Save</button>
</div>

</ng-template>

Best way I have found. Put #lgModal or some other variable name in your modal.

In your view:

<div bsModal #lgModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" (click)="lgModal.hide()" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Large modal</h4>
      </div>
      <div class="modal-body">
        ...
      </div>
    </div>
  </div>
</div>

In your component

import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {CORE_DIRECTIVES} from '@angular/common';
// todo: change to ng2-bootstrap
import {MODAL_DIRECTIVES, BS_VIEW_PROVIDERS} from 'ng2-bootstrap/ng2-bootstrap';
import {ModalDirective} from 'ng2-bootstrap/ng2-bootstrap';


@Component({
  selector: 'modal-demo',
  directives: [MODAL_DIRECTIVES, CORE_DIRECTIVES],
  viewProviders:[BS_VIEW_PROVIDERS],
  templateUrl: '/app/components/modals/modalDemo.component.html'
})
export class ModalDemoComponent implements AfterViewInit{

  @ViewChild('childModal') public childModal: ModalDirective;
  @ViewChild('lgModal') public lgModal: ModalDirective;

  public showChildModal():void {
    this.childModal.show();
  }

  public hideChildModal():void {
    this.childModal.hide();
  }

  ngAfterViewInit() {
      this.lgModal.show();
  }

}

Here is my full implementation of modal bootstrap angular2 component:

I assume that in your main index.html file (with <html> and <body> tags) at the bottom of <body> tag you have:

  <script src="assets/js/jquery-2.1.1.js"></script>
  <script src="assets/js/bootstrap.min.js"></script>

modal.component.ts:

import { Component, Input, Output, ElementRef, EventEmitter, AfterViewInit } from '@angular/core';

declare var $: any;// this is very importnant (to work this line: this.modalEl.modal('show')) - don't do this (becouse this owerride jQuery which was changed by bootstrap, included in main html-body template): let $ = require('../../../../../node_modules/jquery/dist/jquery.min.js');

@Component({
  selector: 'modal',
  templateUrl: './modal.html',
})
export class Modal implements AfterViewInit {

    @Input() title:string;
    @Input() showClose:boolean = true;
    @Output() onClose: EventEmitter<any> = new EventEmitter();

    modalEl = null;
    id: string = uniqueId('modal_');

    constructor(private _rootNode: ElementRef) {}

    open() {
        this.modalEl.modal('show');
    }

    close() {
        this.modalEl.modal('hide');
    }

    closeInternal() { // close modal when click on times button in up-right corner
        this.onClose.next(null); // emit event
        this.close();
    }

    ngAfterViewInit() {
        this.modalEl = $(this._rootNode.nativeElement).find('div.modal');
    }

    has(selector) {
        return $(this._rootNode.nativeElement).find(selector).length;
    }
}

let modal_id: number = 0;
export function uniqueId(prefix: string): string {
    return prefix + ++modal_id;
}

modal.html:

<div class="modal inmodal fade" id="{{modal_id}}" tabindex="-1" role="dialog"  aria-hidden="true" #thisModal>
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header" [ngClass]="{'hide': !(has('mhead') || title) }">
                <button *ngIf="showClose" type="button" class="close" (click)="closeInternal()"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                <ng-content select="mhead"></ng-content>
                <h4 *ngIf='title' class="modal-title">{{ title }}</h4>
            </div>
            <div class="modal-body">
                <ng-content></ng-content>
            </div>

            <div class="modal-footer" [ngClass]="{'hide': !has('mfoot') }" >
                <ng-content select="mfoot"></ng-content>
            </div>
        </div>
    </div>
</div>

And example of usage in client Editor component: client-edit-component.ts:

import { Component } from '@angular/core';
import { ClientService } from './client.service';
import { Modal } from '../common';

@Component({
  selector: 'client-edit',
  directives: [ Modal ],
  templateUrl: './client-edit.html',
  providers: [ ClientService ]
})
export class ClientEdit {

    _modal = null;

    constructor(private _ClientService: ClientService) {}

    bindModal(modal) {this._modal=modal;}

    open(client) {
        this._modal.open();
        console.log({client});
    }

    close() {
        this._modal.close();
    }

}

client-edit.html:

<modal [title]='"Some standard title"' [showClose]='true' (onClose)="close()" #editModal>{{ bindModal(editModal) }}
    <mhead>Som non-standart title</mhead>
    Some contents
    <mfoot><button calss='btn' (click)="close()">Close</button></mfoot>
</modal>

Ofcourse title, showClose, mhead and mfoot ar optional parameters.

I'm currently using Bootstrap 4.3 in Angular 8 and want to open modal window programmatically (without actually clicking on some button as the official demo shows).

Following method works for me: The general idea is to create a button associated to a modal window. First make sure after you click this button, it can open the modal. Then give this button tag an id using hashtag, for example #hiddenBtn . In component ts file, import ViewChild from @angular/core and write below code:

@ViewChild('hiddenBtn', {static: false}) myHiddenBtn;

After that, whenever you want to open this modal window in your component ts code, write following code to simulate click operation

this.myHiddenBtn.nativeElement.click();

I do not feel there is anything wrong with using JQuery with angular and bootstrap, since it is included when adding bootstrap.

  1. Add the $ right after the imports like this


import {.......

declare var $: any;

@component.....
  1. modal should have an id like this

<div id="errorModal" class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" ..............

  1. then have a method like this

showErrorModal() { $("#errorModal").modal('show'); }

  1. call the method on a button click or anywhere you wish

Think I found the correct way to do it using ngx-bootstrap . First import following classes:

import { ViewChild } from '@angular/core';
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';

Inside the class implementation of your component add a @ViewCild property, a function to open the modal and do not forget to setup modalService as a private property inside the components class constructor:

@ViewChild('editSomething') editSomethingModal : TemplateRef<any>;
...

modalRef: BsModalRef;
openModal(template: TemplateRef<any>) {
  this.modalRef = this.modalService.show(template);
}
...
constructor(
private modalService: BsModalService) { }

The 'editSomething' part of the @ViewChild declaration refers to the component template file and its modal template implementation ( #editSomething ):

...
<ng-template #editSomething>
  <div class="modal-header">
  <h4 class="modal-title pull-left">Edit ...</h4>
  <button type="button" class="close pull-right" aria-label="Close" 
   (click)="modalRef.hide()">
    <span aria-hidden="true">&times;</span>
  </button>
  </div>

  <div class="modal-body">
    ...
  </div>


  <div class="modal-footer">
    <button type="button" class="btn btn-default"
        (click)="modalRef.hide()"
        >Close</button>
  </div>
</ng-template>

And finaly call the method to open the modal wherever you want like so:

console.log(this.editSomethingModal);
this.openModal( this.editSomethingModal );

this.editSomethingModal is a TemplateRef that could be shown by the ModalService.

Et voila! The modal defined in your component template file is shown by a call from inside your component class implementation. In my case I used this to show a modal from inside an event handler.

The Way i used to do it without lots of coding is.. I have the hidden button with the id="employeeRegistered"

On my .ts file I import ElementRef from '@angular/core'

Then after I process everything on my (click) method do as follow:

this.el.nativeElement.querySelector('#employeeRegistered').click();

then the modal displays as expected..

For me I had to settimeout in addition to @arjun-sk solution's ( link ), as I was getting the error

setTimeout(() => {
      this.modalService.open(this.loginModal, { centered: true })
    }, 100); 

I am using a variable to control show and hide and rely on the button the open the modal

ts code:

showModel(){
  this.showModal = true;
}

html:

<button type="button" data-toggle="modal" data-target="#myModal" (click)="showModel()>Open Modal</button>

<div *ngIf="showModal" >
  <div id="myModal" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-body">
                <p>Some text in the modal.</p>
            </div>
        </div>
    </div>
</div>

We can use jquery to open bootstrap modal.

ngAfterViewInit() { 
      $('#scanModal').modal('show'); 
}

@ng-bootstrap/ng-bootstrap npm I m using for this as in the project bootstrap is used, for material, we used dialog

HTML Code

  <span (click)="openModal(modalRef)" class="form-control input-underline pl-3 ">Open Abc Modal
 </span>

Modal template

<ng-template class="custom-modal"  #modalRef let-c="close" let-d="dismiss">
   <div class="modal-header custom-modal-head"><h4 class="modal-title">List of Countries</h4>
     <button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
         <img src="assets/actor/images/close.png" alt="">
      </button>
  </div>
  <div class="modal-body country-select">
       <div class="serch-field">
           <div class="row">
               <div class="col-md-12">
                 <input type="text"  class="form-control input-underline pl-3" placeholder="Search Country"
                    [(ngModel)]="countryWorkQuery" [ngModelOptions]="{standalone: true}">
                 <ul *ngIf="countries" class="ng-star-inserted">
                   <li (click)="setSelectedCountry(cntry, 'work');d('Cross click');" class="cursor-pointer"
                   *ngFor="let cntry of countries | filterNames:countryWorkQuery ">{{cntry.name}}</li>
                 </ul>
                 <span *ngIf="!modalSpinner && (!countries || countries.length<=0)">No country found</span>
                 <span *ngIf="modalSpinner" class="loader">
                     <img src="assets/images/loader.gif" alt="loader">
                 </span>
               </div>
             </div>
       </div>
 </div>
</ng-template>

Ts File

import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';

constructor(
    private modalService: NgbModal
  ) { }

  openModal(modalContent){
     this.modalService.open(modalContent, { centered: true});
   }

Simply, npm install --save @types/bootstrap try to match typing version with your bootstrap version. Eg you have Bootstrap 4.3.1 then npm install --save @types/bootstrap@4.3.1

Let me explain the solution. Bit tricky....... Parent HTML File........

<!-- parent component html -->
your code....
<div class="d-flex align-items-center flex-nowrap justify-content-end">
    <button (click)="openCancelStandingOrder(line)" class="btn btn-primary mx-1" type="button">Delete</button>
</div>
<div *ngIf="isCancelStandingOrderOpen">
    <child-component [data]="data" (onCloseModel)="onCloseModal($event)"></child-component>
</div>

Parent TS File

export class ParentComponent {
isCancelStandingOrderOpen: boolean = false;
data: any;
// ....
fetchData() {
// API Call
}

openCancelStandingOrder(line) {
this.isCancelStandingOrderOpen = true;
this.data = line;
}

onCloseModal(reload) {
// prevent unnessecery api calls
if (reload) {

// fetch list data again
this.fetchData();
}

// Do needful

}
}

Child HTML File

<ng-template #cancelStandingOrderModal let-modal>
    <div class="modal-header">
        <h4 class="modal-title" id="modal-basic-title">Title</h4>
        <button type="button" class="btn-close" aria-label="Close" (click)="onDismiss(modal)"></button>
    </div>
    <div class="modal-body">
        <!--  your content here -->
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-outline-success" (click)="onSubmit(modal)">Save</button>
        <button type="button" class="btn btn-outline-dark" (click)="onExit(modal)">Cancel</button>
    </div>
</ng-template>

Child TS File

export class ChildComponent {
// ...
@Input() data: any; // Get data from parent
@Output() public onCloseModal: EventEmitter<boolean> = new EventEmitter();
    @ViewChild('cancelStandingOrderModal', { static: false }) public formModal: TemplateRef<any>; // Note: Target html
        instance

        // Using bootstrap modals: https://ng-bootstrap.github.io/#/components/modal/examples
        constructor(private modalService: NgbModal) { }

        ngOnInit() {
        // Any data manipulation
        }

        ngAfterViewInit() {
        this.openModal();
        }

        openModal() {
        this.modalService.open(this.formModal, {
        backdrop: false,
        centered: true,
        size: 'lg',
        keyboard: false, // disable ESC key to close
        });
        }

        onSubmit(modal) {
        // Do needful.. api calls etc....
        // ...
        this.closeModel(modal, true)
        }

        onExit(modal) {
        // Execute any mathod befor closing modal
        // like unsaved data alert etc.
        this.closeModel(modal, false)
        }


        onDismiss(modal) {
        this.closeModel(modal, false)
        }

        closeModel(modal: any, reload: boolean = false) {
        this.onCloseModal.emit(reload)
        modal.close('close');
        }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM