Skip to content

Commit

Permalink
feat(modal): resolve modal data before OnInit (#2600)
Browse files Browse the repository at this point in the history
fixes #2530
fixes #2733
  • Loading branch information
IlyaSurmay authored and valorkin committed Jan 18, 2018
1 parent 446587e commit bf6361e
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';

Expand All @@ -11,18 +11,17 @@ export class DemoModalServiceFromComponent {
constructor(private modalService: BsModalService) {}

openModalWithComponent() {
const list = [
'Open a modal with component',
'Pass your data',
'Do something else',
'...'
];
this.bsModalRef = this.modalService.show(ModalContentComponent);
this.bsModalRef.content.title = 'Modal with component';
this.bsModalRef.content.list = list;
setTimeout(() => {
list.push('PROFIT!!!');
}, 2000);
const initialState = {
list: [
'Open a modal with component',
'Pass your data',
'Do something else',
'...'
],
title: 'Modal with component'
};
this.bsModalRef = this.modalService.show(ModalContentComponent, {initialState});
this.bsModalRef.content.closeBtnName = 'Close';
}
}

Expand All @@ -43,12 +42,19 @@ export class DemoModalServiceFromComponent {
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" (click)="bsModalRef.hide()">Close</button>
<button type="button" class="btn btn-default" (click)="bsModalRef.hide()">{{closeBtnName}}</button>
</div>
`
})
export class ModalContentComponent {

export class ModalContentComponent implements OnInit {
title: string;
closeBtnName: string;
list: any[] = [];

constructor(public bsModalRef: BsModalRef) {}

ngOnInit() {
this.list.push('PROFIT!!!');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
and smart defaults.</p>

<docs-section [content]="componentContent"></docs-section>
</demo-section>
</demo-section>
4 changes: 2 additions & 2 deletions demo/src/app/components/+modal/modal-section.list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ export const demoComponentContent: ContentSection[] = [
description: `<p>Creating a modal with component just as easy as it is with template. Just pass your component
in <code>.show()</code> method as in example, and don't forget to include your component to
<code>entryComponents</code> of your NgModule<br> If you passed a component
to <code>.show()</code> you can get access to opened modal by injecting BsModalRef. See example for
more info</p>`,
to <code>.show()</code> you can get access to opened modal by injecting BsModalRef. Also you can pass data
in your modal by adding <code>initialState</code> field in config. See example for more info</p>`,
outlet: DemoModalServiceFromComponent
},
{
Expand Down
20 changes: 13 additions & 7 deletions demo/src/ng-api-doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -622,12 +622,6 @@ export const ngdoc: any = {
"type": "string",
"description": "<p>CSS class which will be applied to datepicker container,\nusually used to set color theme</p>\n"
},
{
"name": "locale",
"defaultValue": "en",
"type": "string",
"description": "<p>Allows to globally set default locale of datepicker,\nsee documentation on how to enable custom locales</p>\n"
},
{
"name": "maxDate",
"type": "Date",
Expand Down Expand Up @@ -760,6 +754,13 @@ export const ngdoc: any = {
}
]
},
"BsLocaleService": {
"fileName": "src/datepicker/bs-locale.service.ts",
"className": "BsLocaleService",
"description": "",
"methods": [],
"properties": []
},
"DatePickerInnerComponent": {
"fileName": "src/datepicker/datepicker-inner.component.ts",
"className": "DatePickerInnerComponent",
Expand Down Expand Up @@ -1680,7 +1681,7 @@ export const ngdoc: any = {
},
{
"name": "config",
"type": "any"
"type": "ModalOptions"
}
],
"returnType": "BsModalRef"
Expand Down Expand Up @@ -1735,6 +1736,11 @@ export const ngdoc: any = {
"type": "string",
"description": "<p>Css class for opened modal</p>\n"
},
{
"name": "data",
"type": "Object",
"description": "<p>Modal data</p>\n"
},
{
"name": "ignoreBackdropClick",
"type": "boolean",
Expand Down
29 changes: 13 additions & 16 deletions src/component-loader/component-loader.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,23 @@ export class ComponentLoader<T> {
}

// todo: appendChild to element or document.querySelector(this.container)
show(
opts: {
content?: string | TemplateRef<any>;
context?: any;
[key: string]: any;
} = {}

show(opts: {
content?: string | TemplateRef<any>;
context?: any;
initialState?: any; [key: string]: any;
} = {}
): ComponentRef<T> {

this._subscribePositioning();
this._innerComponent = null;

if (!this._componentRef) {
this.onBeforeShow.emit();
this._contentRef = this._getContentRef(opts.content, opts.context);
const injector = ReflectiveInjector.resolveAndCreate(
this._providers,
this._injector
);
this._contentRef = this._getContentRef(opts.content, opts.context, opts.initialState);
const injector = ReflectiveInjector.resolveAndCreate(this._providers, this._injector);

this._componentRef = this._componentFactory.create(
injector,
this._contentRef.nodes
);
this._componentRef = this._componentFactory.create(injector, this._contentRef.nodes);
this._applicationRef.attachView(this._componentRef.hostView);
// this._componentRef = this._viewContainerRef
// .createComponent(this._componentFactory, 0, injector, this._contentRef.nodes);
Expand Down Expand Up @@ -337,7 +332,8 @@ export class ComponentLoader<T> {

private _getContentRef(
content: string | TemplateRef<any> | any,
context?: any
context?: any,
initialState?: any
): ContentRef {
if (!content) {
return new ContentRef([]);
Expand Down Expand Up @@ -366,6 +362,7 @@ export class ComponentLoader<T> {
this._injector
);
const componentRef = contentCmptFactory.create(modalContentInjector);
Object.assign(componentRef.instance, initialState);
this._applicationRef.attachView(componentRef.hostView);

return new ContentRef(
Expand Down
4 changes: 2 additions & 2 deletions src/modal/bs-modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class BsModalService {
}

/** Shows a modal */
show(content: string | TemplateRef<any> | any, config?: any): BsModalRef {
show(content: string | TemplateRef<any> | any, config?: ModalOptions): BsModalRef {
this.modalsCount++;
this._createLoaders();
this.config = Object.assign({}, modalConfigDefaults, config);
Expand Down Expand Up @@ -109,7 +109,7 @@ export class BsModalService {
.provide({ provide: BsModalRef, useValue: bsModalRef })
.attach(ModalContainerComponent)
.to('body')
.show({ content, isAnimated: this.config.animated, bsModalService: this });
.show({content, isAnimated: this.config.animated, initialState: this.config.initialState, bsModalService: this});
modalContainerRef.instance.level = this.getModalsCount();
bsModalRef.hide = () => {
modalContainerRef.instance.hide();
Expand Down
7 changes: 6 additions & 1 deletion src/modal/modal-options.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export class ModalOptions {
* Toggle animation
*/
animated?: boolean;
/**
* Modal data
*/
initialState?: Object;
}


Expand All @@ -39,7 +43,8 @@ export const modalConfigDefaults: ModalOptions = {
show: false,
ignoreBackdropClick: false,
class: '',
animated: true
animated: true,
initialState: {}
};

export const CLASS_NAME: any = {
Expand Down

0 comments on commit bf6361e

Please sign in to comment.