【问题标题】:How to create a modal popup that is compatible with Angular 4如何创建与 Angular 4 兼容的模式弹出窗口
【发布时间】:2017-04-21 03:29:26
【问题描述】:

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.

似乎question 的答案中列出的方法仅与 Angular 2 兼容。

我不知道从哪里开始,如果有任何帮助,我将不胜感激!

【问题讨论】:

  • 太棒了,这似乎正是我想要的:)
  • 很高兴它有帮助,您可以接受答案,干杯!!
  • 另请注意,如果解决方案适用于 angular v2,它几乎肯定适用于 angular v4

标签: angular typescript popup modal-dialog


【解决方案1】:

接受的答案增加了对苍蝇的很大依赖性。模态(和非模态)对话框很大程度上是一两个 CSS 类的结果。试试这个“重命名...”示例:

1) 编写父模式和子模式,就好像子模式根本不是模式一样,而只是一个附有 *ngIf 的内联表单。

使用<my-modal>child 的父 HTML:

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

父类。为简洁起见,省略了 @Component 装饰器。 (name 属性属于父类,即使我们没有表单来更改它也会存在。)

export class AppComponent {
    name = "old name";

    showIt = false;
    showModal() {
        this.showIt = true;
    }
    closeModal(newName: string) {
        this.showIt = false;
        if (newName) this.name = newName;
    }

}

子成为模态组件。 @Component 装饰器和导入再次省略。

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

模态化之前的子 HTML。

<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) 这是子级的 CSS,但它可以放在全局样式表中,以便在整个应用程序中重复使用。它是一个名为modal 的单一类,用于&lt;div&gt; 元素。

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

但是modal CSS 类不会阻止与它下面的页面交互。 (所以它在技术上创建了一个无模式对话框。)所以我们在模式下方放置一个overlay 来吸收和忽略鼠标活动。 overlay 也适用于 &lt;div&gt; 元素。

.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) 在子 HTML 中使用 modaloverlay

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

就是这样。基本上 2 个 CSS 类,您可以使任何组件成为模态。事实上,您可以在运行时将组件显示为内联或模式,只需使用 ngClass[class.modal]="showAsModalBoolean" 更改 CSS 类的存在即可。

您可以更改此设置,以便孩子控制显示/隐藏逻辑。将 *ngIf、showIt 和 show() 函数移到子项中。在父级中添加@ViewChild(MyModalComponent) renameModal: MyModalComponent;,然后父级可以强制调用this.renameModal.show(this.name); 并根据需要重新连接初始化并包含div。

child-modal 可以将信息返回给父函数,如上所示,或者子函数的 show() 方法可以接受回调或返回 Promise,根据口味。

要知道的两件事:

如果&lt;my-modal&gt; 上有*ngIf,this.renameModal.show(..); 将不起作用,因为它不存在以公开函数开始。 *ngIf 会删除整个组件、show() 函数和所有组件,因此如果出于某种原因需要,请改用 [hidden]

Modals-on-modals 会有 z-index 问题,因为它们都共享相同的 z-index。这可以通过[style.z-index]="calculatedValue" 或类似方式解决。

【讨论】:

  • 我真的很喜欢这个答案,因为它轻巧灵活,而且它是为了教你一些东西而不是使用一个庞大的框架来完成一个小任务。
  • 我也在尝试遵循此代码,但不明白谁应该捕获发出的事件?父 HTML 的某些部分是否处理此问题?
  • 父级的 HTML 有 &lt;my-modal (close)="closeModal($event)"&gt;,这是子级发出的 close 事件被捕获并路由到父级控制器的 closeModal 函数的地方。
  • 说实话,知道我们可以使用 Angular 材料来完成这项任务对我来说几乎是无用的,如果不是有害的话。然而,这个答案缺乏的是通常人们不会将模态用作嵌入式组件,而是始终将它们用作服务,例如。 modalObject.popup() 其中modalObject 可以即时初始化。因此它在应用模板中应该没有这个组件的踪迹。
  • 喜欢这个答案。简单、可定制且不依赖于其他库.. 谢谢..
【解决方案2】:

查看Angular Material Dialogue,这里是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>) {}
}

【讨论】:

  • 我在子组件中而不是直接在根中调用 openDialog() 函数,所以我不想在 main.ts 中引导对话框组件(因为这给了我过多的错误提示此组件与任何元素都不匹配)。我是否需要为子组件提供类似于它自己的 module.ts 的东西?我该如何解决这个问题?
  • 谢谢。经过一番搜索,我找到了解决方案。我必须添加“entryComponents:[DialogResultExampleDialog]”而不是引导它
  • 这不起作用。找不到模块'@angular/material'。
  • 插件无法为我加载。
  • @paulya,谢谢你让我知道,更新了网址,干杯!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2017-08-28
  • 2014-05-26
  • 1970-01-01
相关资源
最近更新 更多