如何在Angular 2中使用代码打开模态框?

47

通常我们在<button>中使用data-target="#myModal"来打开模态框。现在我需要使用代码来控制何时打开模态框。

如果我使用[hidden]*ngIf来显示它,我需要删除class="modal fade",否则模态框将永远不会显示。像这样:

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

然而,在这种情况下,如果移除class="modal fade",模态框将不会淡入并且背景没有遮罩层。更糟糕的是,它将显示在屏幕底部而非屏幕中心。

有没有办法保留class="modal fade"并使用代码打开它?

<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>

为什么在模态框中要使用 [hidden] - Pardeep Jain
@PardeepJain 正如我所说,[hidden] 和 class="modal fade" 一起使用时,即使 [hidden]="false",模态框也永远不会显示。如果您想使用 [hidden],则需要删除 class="modal fade"。 - Hongbo Miao
16个回答

61

这是我找到的一种方法。你可以添加一个隐藏的按钮:

<button id="openModalButton" [hidden]="true" data-toggle="modal" data-target="#myModal">Open Modal</button>
然后使用代码来“点击”按钮以打开模态窗口:
document.getElementById("openModalButton").click();

这种方法可以保持模态框的Bootstrap样式和渐变动画。


19
这在编译时不起作用,也不适用于TypeScript。这有点像hackish。 - Judson Terrell
链接 http://valor-software.com/ng2-bootstrap/#/modals 今天返回了404错误... - gogognome
@gogognome 谢谢,我刚刚删除了那个链接,因为现在有很多可用的软件包供使用者选择。 - Hongbo Miao
1
非常感谢。最酷的解决方案。我在Angular中不使用第三方引导程序,只是从官方网站复制链接。我不喜欢太多的代码混乱,只有在后端数据加载完成后才打开弹出窗口。这正是我一直在寻找的。 - Nabin Kumar Khatiwada

34

在 index.html 文件的 script 标签中像往常一样引入 jQuery。

在所有导入但在声明 @Component 之前添加:

declare var $: any;

现在你可以在 Angular 2 TypeScript 代码中的任何地方自由使用 jQuery:

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

参考资料: https://dev59.com/AV0a5IYBdhLWcg3wLWGx#38246116


2
我是这样做的。Bootstrap 3 在某种程度上依赖于 jQuery。 - yonexbat
4
最佳答案无需安装第三方包。在使用Bootstrap时应安装jQuery,因此最好在控制器中使用它,这种方法也在Bootstrap文档中。谢谢。 - deanwilliammills
不要忘记链接或安装bootstrap.js。 - Leandro Bardelli
jQuery 不应该与 Angular 2+ 一起使用。 - sagar1025

12

以下答案是针对最新的ng-bootstrap参考。

安装

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 { }

组件控制器

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);
  }

}

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>

1
太好了!我没有注意到TemplateRef<any>; // Note: TemplateRef,但这很重要。谢谢,Arjun - Hamid Hoseini

12

Angular 2或4 中实现这一点的简便方法(假设您使用的是Bootstrap 4

组件.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';
}

1
请问您能具体说明在您的解决方案中,您假设使用了Bootstrap 4而不是3吗?我正在使用版本3,这个解决方案对我仍有效,所以我想我可能错过了一些细节,希望了解更多 :) - MaxAxeHax
@MaxAxeHax 我使用词语“假设使用bootstarp 4”,以防万一之前或即将发布的bootstrap隐藏和显示类发生更改,那么您只需要在openModel和closeModel函数中替换该类即可。 - Umang Patwa
4
对我没用。无论是片段还是基于它的代码都不行。 - Tomasz O.
不起作用。无论是片段还是基于 i 的代码。 - Fatih Doğan

7

我发现最好的方法是,在你的模态框中放置#lgModal或其他变量名。

在你的视图中:

<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>

在你的组件中

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();
  }

}

5

这是我的完整的基于Bootstrap 和Angular2的Modal组件实现:

我假设您在主索引文件index.html(包含<html><body>标签)中,在<body>标签底部包含以下代码:

  <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>

在客户端编辑组件中使用的示例: 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>

当然,标题、showClose、mhead和mfoot都是可选参数。

请您看一下这个 https://stackblitz.com/edit/angular-xesgxe 当点击 input 时,我想显示一个模态框。但编译器找不到 this.el.modalthis.el.nativeElement.modal() - Manu Chadha
ngAfterViewInit 方法和 open/close 方法中,我实际上使用了它。然而,在这个答案中,目标是提供一个可工作的“模态”组件(带有示例用法)- 然而,这是两年前的事情,现在可能已经过时了。 - Kamil Kiełczewski
是的,我现在明白了。我担心混合使用jquery和angular代码,但这是我唯一能够使其工作的方法。如果你找到更多Angular的解决方案,请务必更新。我也会这样做。 - Manu Chadha
你能帮我理解为什么这行代码declare var $: any;很重要吗?我本以为因为我已经在项目中引入了jquery,所以应该可以在任何地方使用$。另外,你提到的因为这个覆盖了被Bootstrap修改过的jQuery是什么意思?Bootstrap是否有自己的JQuery实现? - Manu Chadha
@ManuChadha 我问了一个更一般的类似问题:https://dev59.com/N6vka4cB1Zd3GeqPwabW - Kamil Kiełczewski
显示剩余2条评论

5

我认为在使用angular和bootstrap时使用JQuery并没有任何问题,因为当添加bootstrap时,它已经被包含进去了。

  1. 像这样在导入之后添加$


import {.......

declare var $: any;

@component.....
  1. 模态框应该像这样拥有一个id

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

  1. 然后要有这样一个方法

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

  1. 在按钮点击或任何您想要的地方调用该方法

4

我目前在 Angular 8 中使用 Bootstrap 4.3,想要以编程方式打开模态窗口(而不是像官方演示所示的实际单击某个按钮)。

以下方法适用于我: 一般的思路是创建与模态窗口相关联的按钮。 首先确保在单击此按钮后,它可以打开模态窗口。 然后使用哈希标记为此按钮标记一个 id,例如 #hiddenBtn。 在组件 TS 文件中,import ViewChild from @angular/core 并编写以下代码:

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

之后,每当您想在组件的ts代码中打开此模态窗口时,请编写以下代码来模拟单击操作

this.myHiddenBtn.nativeElement.click();

对我有用。谢谢! - Aspiring Dev
不错的解决方案!即使不是 Angular 的方式 :) - Torsten Barthel

2

我想我已经找到了使用ngx-bootstrap的正确方法。首先导入以下类:

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

在您的组件类实现中,添加一个@ViewChild属性和一个用于打开模态框的函数。不要忘记在组件类构造函数中设置modalService为私有属性:
@ViewChild('editSomething') editSomethingModal : TemplateRef<any>;
...

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

@ViewChild声明中的“editSomething”部分指的是组件模板文件以及其模态模板实现(#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>

最后,您可以在需要打开模态框的任何地方调用该方法:
console.log(this.editSomethingModal);
this.openModal( this.editSomethingModal );

this.editSomethingModal是一个TemplateRef,可以通过ModalService显示。

完成了!在组件模板文件中定义的模态框可以通过组件类实现内部调用进行显示。在我的情况下,我使用它来从事件处理程序内部显示模态框。


0

简单来说,npm install --save @types/bootstrap 会尝试将类型版本与您的 Bootstrap 版本匹配。例如,如果您有 Bootstrap 4.3.1,则应使用 npm install --save @types/bootstrap@4.3.1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接