+
+
+ This is a non-service html modal
`
})
export class NzDemoModalServiceComponent {
- tplModal: ModalPublicAgent;
+ tplModal: NzModalRef;
tplModalButtonLoading = false;
+ htmlModalVisible = false;
constructor(private modalService: NzModalService) { }
@@ -80,15 +86,20 @@ export class NzDemoModalServiceComponent {
},
nzFooter: [{
label: 'change component tilte from outside',
- onClick: (componentInstance: NzModalCustomComponent) => {
+ onClick: (componentInstance) => {
componentInstance.title = 'title in inner component is changed';
}
}]
});
+ modal.afterOpen.subscribe(() => console.log('[afterOpen] emitted!'));
+
+ // Return a result when closed
+ modal.afterClose.subscribe((result) => console.log('[afterClose] The result is:', result));
+
// delay until modal instance created
window.setTimeout(() => {
- const instance = modal.getContentComponentRef().instance as NzModalCustomComponent;
+ const instance = modal.getContentComponent();
instance.subtitle = 'sub title is changed';
}, 2000);
}
@@ -130,6 +141,23 @@ export class NzDemoModalServiceComponent {
]
});
}
+
+ openAndCloseAll(): void {
+ let pos = 0;
+
+ [ 'create', 'info', 'success', 'error' ].forEach((method) => this.modalService[method]({
+ nzMask: false,
+ nzTitle: `Test ${method} title`,
+ nzContent: `Test content: ${method}`,
+ nzStyle: { position: 'absolute', top: `${pos * 70}px`, left: `${(pos++) * 300}px` }
+ }));
+
+ this.htmlModalVisible = true;
+
+ this.modalService.afterAllClose.subscribe(() => console.log('afterAllClose emitted!'));
+
+ window.setTimeout(() => this.modalService.closeAll(), 2000);
+ }
}
@Component({
@@ -149,9 +177,9 @@ export class NzModalCustomComponent {
@Input() title: string;
@Input() subtitle: string;
- constructor(private modal: ModalPublicAgent) { }
+ constructor(private modal: NzModalRef) { }
destroyModal(): void {
- this.modal.destroy();
+ this.modal.destroy({ data: 'this the result data' });
}
}
diff --git a/components/modal/doc/index.en-US.md b/components/modal/doc/index.en-US.md
index c228e4f98b7..70b7f4019d9 100644
--- a/components/modal/doc/index.en-US.md
+++ b/components/modal/doc/index.en-US.md
@@ -14,7 +14,7 @@ getting feedback or information purposes.
Additionally, if you need show a simple confirmation dialog, you can use `NzModalService.confirm()`,
and so on.
-It is recommended to use the `Component` way to pop up the Modal, so that the component logic of the popup layer can be completely isolated from the outer component, and can be reused at any time. In the popup layer component, you can obtain Modal's component instance by injecting `ModalPublicAgent` to control the behavior of the modal box.
+It is recommended to use the `Component` way to pop up the Modal, so that the component logic of the popup layer can be completely isolated from the outer component, and can be reused at any time. In the popup layer component, you can obtain Modal's component instance by injecting `NzModalRef` to control the behavior of the modal box.
## API
@@ -23,14 +23,15 @@ The dialog is currently divided into 2 modes, `normal mode` and `confirm box mod
| Property | Description | Type | Default |
|----|----|----|----|
-| nzAfterClose | Specify a EventEmitter that will be emitted when modal is closed completely. | EventEmitter | - |
+| nzAfterOpen | Specify a EventEmitter that will be emitted when modal opened | EventEmitter | - |
+| nzAfterClose | Specify a EventEmitter that will be emitted when modal is closed completely (Can listen for parameters passed in the close/destroy method) | EventEmitter | - |
| nzBodyStyle | Body style for modal body element. Such as height, padding etc. | object | - |
| nzCancelText | Text of the Cancel button. Set to null to show no cancel button (this value is invalid if the nzFooter parameter is used in normal mode) | string | Cancel |
| nzClosable | Whether a close (x) button is visible on top right of the modal dialog or not. Invalid value in confirm box mode (default will be hidden) | boolean | true |
| nzOkLoading | Whether to apply loading visual effect for OK button or not | boolean | false |
| nzCancelLoading | Whether to apply loading visual effect for Cancel button or not | boolean | false |
| nzFooter | Footer content, set as footer=null when you don't need default buttons. 1. Only valid in normal mode. 2. You can customize the buttons to the maximum extent by passing a `ModalButtonOptions` configuration (see the case or the instructions below). | string TemplateRef ModalButtonOptions | OK and Cancel buttons |
-| nzGetContainer | The mount node for Modal | HTMLElement / () => HTMLElement| Handled by overlay container |
+| nzGetContainer | The mount node for Modal | HTMLElement / () => HTMLElement| A default container |
| nzMask | Whether show mask or not. | boolean | true |
| nzMaskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true |
| nzMaskStyle | Style for modal's mask element. | object | - |
@@ -42,8 +43,8 @@ The dialog is currently divided into 2 modes, `normal mode` and `confirm box mod
| nzWidth | Width of the modal dialog. When using numbers, the default unit is `px` | string number | 520 |
| nzWrapClassName | The class name of the container of the modal dialog | string | - |
| nzZIndex | The z-index of the Modal | number | 1000 |
-| nzOnCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button. Note: When created with `NzModalService.create`, this parameter should be passed into the type of function (callback function). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | EventEmitter | - |
-| nzOnOk | Specify a EventEmitter that will be emitted when a user clicks the OK button | EventEmitter | 无 |
+| nzOnCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button (If nzContent is Component, the Component instance will be put in as an argument). Note: When created with `NzModalService.create`, this parameter should be passed into the type of function (callback function). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | EventEmitter | - |
+| nzOnOk | Specify a EventEmitter that will be emitted when a user clicks the OK button (If nzContent is Component, the Component instance will be put in as an argument). Note: When created with `NzModalService.create`, this parameter should be passed into the type of function (callback function). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | EventEmitter | 无 |
| nzContent | Content | string / TemplateRef / Component / ng-content | - |
| nzComponentParams | When nzContent is a Component, the attributes in this parameter will be passed to the nzContent instance | object | - |
| nzIconType | Icon type of the Icon component. Only valid in confirm box mode | string | question-circle |
@@ -71,8 +72,8 @@ Consistent with the above API, some property types or initial values are differe
| Property | Description | Type | Default |
|------------|----------------|------------------|---------------|
-| nzOnOk | Specify a EventEmitter that will be emitted when a user clicks the OK button. This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | function | - |
-| nzOnCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button. This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | function | - |
+| nzOnOk | Specify a EventEmitter that will be emitted when a user clicks the OK button (If nzContent is Component, the Component instance will be put in as an argument.). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | function | - |
+| nzOnCancel | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button (If nzContent is Component, the Component instance will be put in as an argument.). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing) | function | - |
| nzWidth | Width of the modal dialog | string / number | 416 |
| nzMaskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | false |
@@ -80,23 +81,35 @@ All the `NzModalService.method`s will return a reference, and then we can close
```ts
constructor(modal: NzModalService) {
- const ref: ModalPublicAgent = modal.info();
- ref.destroy(); // Note: This dialog will be destroyed directly
+ const ref: NzModalRef = modal.info();
+ ref.close(); // Or ref.destroy(); This dialog will be destroyed directly
}
```
### Related type definition
-#### ModalPublicAgent (used for control dialogs)
+#### Other Methods/Attributes for NzModalService
-The dialog created by the service method `NzModalService.xxx()` will return a `ModalPublicAgent` object that is used to manipulate the dialog (this object can also be obtained by dependency injection `ModalPublicAgent` if `nzContent` is used as Component) , This object has the following methods:
+| Methods/Attributes | Description | Type |
+|----|----|
+| openModals | All currently open Modal list | NzModalRef[] |
+| afterAllClose | Callback called after all Modals closed completely | Observable<void> |
+| closeAll() | Close all modals | function |
+
+#### NzModalRef
+
+> NzModalRef object is used to control dialogs and communicate with inside content
+
+The dialog created by the service method `NzModalService.xxx()` will return a `NzModalRef` object that is used to manipulate the dialog (this object can also be obtained by dependency injection `NzModalRef` if `nzContent` is used as Component) , This object has the following methods:
| Method | Description |
|----|----|
+| afterOpen | Same as nzAfterOpen but of type Observable<void> |
+| afterClose | Same as nzAfterClose, but of type Observable<result:any> |
| open() | Open (display) dialog box. Calling this function will fail if the dialog is already destroyed |
| close() | Close (hide) the dialog. Note: When used for a dialog created as a service, this method will destroy the dialog directly (as with the destroy method) |
| destroy() | Destroy the dialog. Note: Used only for dialogs created by the service (non-service created dialogs, this method only hides the dialog) |
-| getContentComponentRef() | Gets a Component reference (of type `ComponentRef`) in the contents of the dialog for `nzContent`. Note: When the dialog is not initialized (`ngOnInit` is not executed), this function will return `undefined` |
+| getContentComponent() | Gets the Component instance in the contents of the dialog for `nzContent`. Note: When the dialog is not initialized (`ngOnInit` is not executed), this function will return `undefined` |
#### ModalButtonOptions (used to customize the bottom button)
diff --git a/components/modal/doc/index.zh-CN.md b/components/modal/doc/index.zh-CN.md
index d47fbd485ff..a8068a701a6 100644
--- a/components/modal/doc/index.zh-CN.md
+++ b/components/modal/doc/index.zh-CN.md
@@ -15,7 +15,7 @@ title: Modal
推荐使用加载Component的方式弹出Modal,这样弹出层的Component逻辑可以与外层Component完全隔离,并且做到可以随时复用,
-在弹出层Component中可以通过依赖注入`ModalPublicAgent`方式直接获取模态框的组件实例,用于控制在弹出层组件中控制模态框行为。
+在弹出层Component中可以通过依赖注入`NzModalRef`方式直接获取模态框的组件实例,用于控制在弹出层组件中控制模态框行为。
## API
@@ -23,14 +23,15 @@ title: Modal
| 参数 | 说明 | 类型 | 默认值 |
|----|----|----|----|
-| nzAfterClose | Modal 完全关闭后的回调 | EventEmitter | 无 |
+| nzAfterOpen | Modal 打开后的回调 | EventEmitter | 无 |
+| nzAfterClose | Modal 完全关闭后的回调,可监听close/destroy方法传入的参数 | EventEmitter | 无 |
| nzBodyStyle | Modal body 样式 | object | 无 |
| nzCancelText | 取消按钮文字。设为 null 表示不显示取消按钮(若在普通模式下使用了 nzFooter 参数,则该值无效) | string | 取消 |
| nzClosable | 是否显示右上角的关闭按钮。确认框模式下该值无效(默认会被隐藏) | boolean | true |
| nzOkLoading | 确定按钮 loading | boolean | false |
| nzCancelLoading | 取消按钮 loading | boolean | false |
| nzFooter | 底部内容。1. 仅在普通模式下有效。 2. 可通过传入 ModalButtonOptions 来最大程度自定义按钮(详见案例或下方说明)。 3. 当不需要底部时,可以设为 null | string TemplateRef ModalButtonOptions | 默认的确定取消按钮 |
-| nzGetContainer | 指定 Modal 挂载的 HTML 节点 | HTMLElement () => HTMLElement| 默认在overlay容器中 |
+| nzGetContainer | 指定 Modal 挂载的 HTML 节点 | HTMLElement () => HTMLElement| 默认容器 |
| nzMask | 是否展示遮罩 | boolean | true |
| nzMaskClosable | 点击蒙层是否允许关闭 | boolean | true |
| nzMaskStyle | 遮罩样式 | object | 无 |
@@ -42,8 +43,8 @@ title: Modal
| nzWidth | 宽度。使用数字时,默认单位为px | string number | 520 |
| nzWrapClassName | 对话框外层容器的类名 | string | 无 |
| nzZIndex | 设置 Modal 的 `z-index` | number | 1000 |
-| nzOnCancel | 点击遮罩层或右上角叉或取消按钮的回调。注:当以`NzModalService.create`创建时,此参数应传入function(回调函数)。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | EventEmitter | 无 |
-| nzOnOk | 点击确定回调 | EventEmitter | 无 |
+| nzOnCancel | 点击遮罩层或右上角叉或取消按钮的回调(若nzContent为Component,则将会以该Component实例作为参数)。注:当以`NzModalService.create`创建时,此参数应传入function(回调函数)。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | EventEmitter | 无 |
+| nzOnOk | 点击确定回调(若nzContent为Component,则将会以该Component实例作为参数)。注:当以`NzModalService.create`创建时,此参数应传入function(回调函数)。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | EventEmitter | 无 |
| nzContent | 内容 | string TemplateRef Component ng-content | 无 |
| nzComponentParams | 当nzContent为组件类(Component)时,该参数中的属性将传入nzContent实例中 | object | 无 |
| nzIconType | 图标 Icon 类型。仅 确认框模式 下有效 | string | question-circle |
@@ -70,8 +71,8 @@ title: Modal
| 参数 | 说明 | 类型 | 默认值 |
|------------|----------------|------------------|--------------|
-| nzOnOk | 点击确定按钮时将执行的回调函数。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | function | 无 |
-| nzOnCancel | 点击遮罩层或右上角叉或取消按钮的回调。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | function | 无 |
+| nzOnOk | 点击确定按钮时将执行的回调函数(若nzContent为Component,则将会以该Component实例作为参数)。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | function | 无 |
+| nzOnCancel | 点击遮罩层或右上角叉或取消按钮的回调(若nzContent为Component,则将会以该Component实例作为参数)。该函数可返回promise,待执行完毕或promise结束时,将自动关闭对话框(返回false可阻止关闭) | function | 无 |
| nzWidth | 宽度 | string number | 416 |
| nzMaskClosable | 点击蒙层是否允许关闭 | boolean | false |
@@ -79,23 +80,35 @@ title: Modal
```ts
constructor(modal: NzModalService) {
- const ref: ModalPublicAgent = modal.info();
- ref.destroy(); // 注:这里将直接销毁对话框
+ const ref: NzModalRef = modal.info();
+ ref.close(); // 或 ref.destroy(); 将直接销毁对话框
}
```
### 相关类型定义
-#### ModalPublicAgent(用于控制对话框)
+#### NzModalService的其他方法/属性
-通过服务方式 `NzModalService.xxx()` 创建的对话框,都会返回一个 `ModalPublicAgent` 对象,用于操控该对话框(若使用nzContent为Component时,也可通过依赖注入 `ModalPublicAgent` 方式获得此对象),该对象具有以下方法:
+| 方法/属性 | 说明 | 类型 |
+|----|----|
+| openModals | 当前打开的所有Modal引用列表 | NzModalRef[] |
+| afterAllClose | 所有Modal完全关闭后的回调 | Observable<void> |
+| closeAll() | 关闭所有模态框 | function |
+
+#### NzModalRef
+
+> NzModalRef 对象用于控制对话框以及进行内容间的通信
+
+通过服务方式 `NzModalService.xxx()` 创建的对话框,都会返回一个 `NzModalRef` 对象,用于操控该对话框(若使用nzContent为Component时,也可通过依赖注入 `NzModalRef` 方式获得此对象),该对象具有以下方法:
-| 方法 | 说明 |
+| 方法/属性 | 说明 |
|----|----|
+| afterOpen | 同nzAfterOpen,但类型为Observable<void> |
+| afterClose | 同nzAfterClose,但类型为Observable<result:any> |
| open() | 打开(显示)对话框。若对话框已销毁,则调用此函数将失效 |
-| close() | 关闭(隐藏)对话框。注:当用于以服务方式创建的对话框,此方法将直接 销毁 对话框(同destroy方法) |
-| destroy() | 销毁对话框。注:仅用于服务方式创建的对话框(非服务方式创建的对话框,此方法只会隐藏对话框) |
-| getContentComponentRef() | 获取对话框内容中`nzContent`的Component引用(类型为`ComponentRef`)。注:当对话框还未初始化完毕(`ngOnInit`未执行)时,此函数将返回`undefined` |
+| close(result: any) | 关闭(隐藏)对话框。注:当用于以服务方式创建的对话框,此方法将直接 销毁 对话框(同destroy方法) |
+| destroy(result: any) | 销毁对话框。注:仅用于服务方式创建的对话框(非服务方式创建的对话框,此方法只会隐藏对话框) |
+| getContentComponent() | 获取对话框内容中`nzContent`的Component实例instance。注:当对话框还未初始化完毕(`ngOnInit`未执行)时,此函数将返回`undefined` |
#### ModalButtonOptions(用于自定义底部按钮)
diff --git a/components/modal/modal-public-agent.class.ts b/components/modal/modal-public-agent.class.ts
deleted file mode 100644
index 6c6ec112fd2..00000000000
--- a/components/modal/modal-public-agent.class.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { ComponentRef } from '@angular/core';
-
-import { NzModalComponent } from './nz-modal.component';
-
-/**
- * API class that public to users to handle the modal instance.
- * ModalPublicAgent is aim to avoid accessing to the modal instance directly by users.
- */
-export abstract class ModalPublicAgent {
- abstract open(): void;
- abstract close(): void;
- abstract destroy(): void;
-
- /**
- * Return the ComponentRef of nzContent when specify nzContent as a Component
- * Note: this method may return undefined if the Component has not ready yet. (it only available after Modal's ngOnInit)
- */
- abstract getContentComponentRef(): ComponentRef<{}>;
-
- /**
- * Get the dom element of this Modal
- */
- abstract getElement(): HTMLElement;
-
- /**
- * Get the instance of the Modal itself
- */
- abstract getInstance(): NzModalComponent;
-}
diff --git a/components/modal/nz-modal-control.service.ts b/components/modal/nz-modal-control.service.ts
new file mode 100644
index 00000000000..6bfeb3a44b6
--- /dev/null
+++ b/components/modal/nz-modal-control.service.ts
@@ -0,0 +1,72 @@
+import { Injectable, Optional, SkipSelf } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+import { Subscription } from 'rxjs/Subscription';
+
+import { NzModalRef } from './nz-modal-ref.class';
+
+interface RegisteredMeta {
+ modalRef: NzModalRef;
+ afterOpenSubscription: Subscription;
+ afterCloseSubscription: Subscription;
+}
+
+@Injectable()
+export class NzModalControlService {
+ // Track singleton afterAllClose through over the injection tree
+ get afterAllClose(): Subject {
+ return this.parentService ? this.parentService.afterAllClose : this.rootAfterAllClose;
+ }
+ // Track singleton openModals array through over the injection tree
+ get openModals(): NzModalRef[] {
+ return this.parentService ? this.parentService.openModals : this.rootOpenModals;
+ }
+
+ private rootOpenModals: NzModalRef[] = this.parentService ? null : [];
+ private rootAfterAllClose: Subject = this.parentService ? null : new Subject();
+
+ private rootRegisteredMetaMap: Map = this.parentService ? null : new Map();
+ private get registeredMetaMap(): Map { // Registered modal for later usage
+ return this.parentService ? this.parentService.registeredMetaMap : this.rootRegisteredMetaMap;
+ }
+
+ constructor(
+ @Optional() @SkipSelf() private parentService: NzModalControlService) {}
+
+ // Register a modal to listen its open/close
+ registerModal(modalRef: NzModalRef): void {
+ if (!this.hasRegistered(modalRef)) {
+ const afterOpenSubscription = modalRef.afterOpen.subscribe(() => this.openModals.push(modalRef));
+ const afterCloseSubscription = modalRef.afterClose.subscribe(() => this.removeOpenModal(modalRef));
+
+ this.registeredMetaMap.set(modalRef, { modalRef, afterOpenSubscription, afterCloseSubscription });
+ }
+ }
+
+ // TODO: allow deregister modals
+ // deregisterModal(modalRef: NzModalRef): void {}
+
+ hasRegistered(modalRef: NzModalRef): boolean {
+ return this.registeredMetaMap.has(modalRef);
+ }
+
+ // Close all registered opened modals
+ closeAll(): void {
+ let i = this.openModals.length;
+
+ while (i--) {
+ this.openModals[i].close();
+ }
+ }
+
+ private removeOpenModal(modalRef: NzModalRef): void {
+ const index = this.openModals.indexOf(modalRef);
+
+ if (index > -1) {
+ this.openModals.splice(index, 1);
+
+ if (!this.openModals.length) {
+ this.afterAllClose.next();
+ }
+ }
+ }
+}
diff --git a/components/modal/nz-modal-ref.class.ts b/components/modal/nz-modal-ref.class.ts
new file mode 100644
index 00000000000..fd5f0815e79
--- /dev/null
+++ b/components/modal/nz-modal-ref.class.ts
@@ -0,0 +1,39 @@
+import { ComponentRef, Type } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+
+import { NzModalComponent } from './nz-modal.component';
+
+/**
+ * API class that public to users to handle the modal instance.
+ * NzModalRef is aim to avoid accessing to the modal instance directly by users.
+ */
+export abstract class NzModalRef { // tslint:disable-line:no-any
+ abstract afterOpen: Observable;
+ abstract afterClose: Observable;
+
+ abstract open(): void;
+ abstract close(result?: R): void;
+ abstract destroy(result?: R): void;
+
+ // /**
+ // * Return the ComponentRef of nzContent when specify nzContent as a Component
+ // * Note: this method may return undefined if the Component has not ready yet. (it only available after Modal's ngOnInit)
+ // */
+ // abstract getContentComponentRef(): ComponentRef<{}>;
+
+ /**
+ * Return the component instance of nzContent when specify nzContent as a Component
+ * Note: this method may return undefined if the Component has not ready yet. (it only available after Modal's ngOnInit)
+ */
+ abstract getContentComponent(): T;
+
+ /**
+ * Get the dom element of this Modal
+ */
+ abstract getElement(): HTMLElement;
+
+ /**
+ * Get the instance of the Modal itself
+ */
+ abstract getInstance(): NzModalComponent;
+}
diff --git a/components/modal/nz-modal.component.html b/components/modal/nz-modal.component.html
index da04a591470..2879da0a490 100644
--- a/components/modal/nz-modal.component.html
+++ b/components/modal/nz-modal.component.html
@@ -74,11 +74,11 @@
>{{ button.label }}
-