Skip to content

Commit

Permalink
feat(modal): modal service wip (#2047)
Browse files Browse the repository at this point in the history
fixes #1998
fixes #1995
fixes #1830
fixes #1181
fixes #579 

* feat(modal): modal service wip

* feat(modal): wip, add close buttons attribute support, add ability to open modaol with component

* feat(modal): add config, move creating of loader to constructor, add demo

* fix(modal): fix service path

* fix(modal): fix api-docs

* fix(modal): fix scroll on modals created by service, add docs

* feat(modal): wip, add BsModalService.show output obj

* refactor(modal): change inner component getter

* feat(modal): add BsModalRef and docs

* feat(modal): remove data-attributes, return BsModalRef, update docs

* feat(modal): add docs for BsModalService, BsModalRef, update demo

* feat(modal): add bs4 support

* feat(modal): keep focus inside a modal

* chore(modals): small refactoring (#2128)

* chore(modals): simplify service (#2130)

* chore(modal): view container ref made optional for component loader (#2133)

* fix(modal): fix backdrop flickering

* fix(modal): fix backdrop click on the left/right sides, add class option

* feat(modals): nested modals wip

* fix(modal): fix multiple hide() call

* fix(modal): fix multiple backdrop clicks, fix padding

* fix(modal): fixed padding

* fix(modal): fix page flickering

* feat(modal): add isAnimated support, add service section to demo

* fix(test): fix popover and tyepahead unit tests
  • Loading branch information
IlyaSurmay authored and valorkin committed Jul 18, 2017
1 parent 2fedac2 commit 2d02faa
Show file tree
Hide file tree
Showing 25 changed files with 758 additions and 114 deletions.
5 changes: 4 additions & 1 deletion demo/src/app/components/+modal/demo-modal.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { SharedModule } from '../../shared';
import { ModalSectionComponent } from './modal-section.component';
import { DEMO_COMPONENTS } from './demos';
import { routes } from './demo-modal.routes';
import { ModalContentComponent } from './demos/service-component/service-component';

@NgModule({
declarations: [
ModalSectionComponent,
ModalContentComponent,
...DEMO_COMPONENTS
],
imports: [
Expand All @@ -21,7 +23,8 @@ import { routes } from './demo-modal.routes';
SharedModule,
RouterModule.forChild(routes)
],
exports: [ModalSectionComponent]
exports: [ModalSectionComponent],
entryComponents: [ModalContentComponent]
})
export class DemoModalModule {

Expand Down
29 changes: 26 additions & 3 deletions demo/src/app/components/+modal/demos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@ import { DemoModalSizesComponent } from './sizes/sizes';
import { DemoModalStaticComponent } from './static/static';
import { DemoModalChildComponent } from './child/child';
import { DemoAutoShownModalComponent } from './auto-shown/auto-shown';
import { DemoNestedDropdownsComponent } from '../../+dropdown/demos/nested-dropdowns/nested-dropdowns';
import { DemoModalNestedComponent } from './nested/nested';
import { DemoModalEventsComponent } from './events/events';
import { DemoModalServiceStaticComponent } from './service-template/service-template';
import { DemoModalServiceFromComponent } from './service-component/service-component';
import { DemoModalServiceNestedComponent } from './service-nested/service-nested';
import { DemoModalServiceOptionsComponent } from './service-options/service-options';

export const DEMO_COMPONENTS = [
DemoModalSizesComponent,
DemoModalChildComponent,
DemoModalStaticComponent,
DemoAutoShownModalComponent,
DemoModalEventsComponent,
DemoModalNestedComponent
DemoModalNestedComponent,
DemoModalServiceStaticComponent,
DemoModalServiceFromComponent,
DemoModalServiceNestedComponent,
DemoModalServiceOptionsComponent,
DemoModalEventsComponent
];

export const DEMOS = {
Expand All @@ -39,5 +46,21 @@ export const DEMOS = {
events: {
component: require('!!raw-loader?lang=typescript!./events/events.ts'),
html: require('!!raw-loader?lang=markup!./events/events.html')
},
serviceTemplate: {
component: require('!!raw-loader?lang=typescript!./service-template/service-template.ts'),
html: require('!!raw-loader?lang=markup!./service-template/service-template.html')
},
serviceComponent: {
component: require('!!raw-loader?lang=typescript!./service-component/service-component.ts'),
html: require('!!raw-loader?lang=markup!./service-component/service-component.html')
},
serviceNested: {
component: require('!!raw-loader?lang=typescript!./service-nested/service-nested.ts'),
html: require('!!raw-loader?lang=markup!./service-nested/service-nested.html')
},
serviceOptions: {
component: require('!!raw-loader?lang=typescript!./service-options/service-options.ts'),
html: require('!!raw-loader?lang=markup!./service-options/service-options.html')
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button type="button" class="btn btn-primary" (click)="openModalWithComponent()">Create modal with component</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Component } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';

@Component({
selector: 'demo-modal-service-component',
templateUrl: './service-component.html'
})
export class DemoModalServiceFromComponent {
constructor(private modalService: BsModalService) {}

public openModalWithComponent() {
this.modalService.show(ModalContentComponent);
}
}

/* This is a component which we pass in modal*/

@Component({
selector: 'modal-content',
template: `
<div class="modal-header">
<h4 class="modal-title pull-left">{{title}}</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="bsModalRef.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
This is a modal with component inside.
Click <b>&times;</b> to close modal.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" (click)="bsModalRef.hide()">Close</button>
</div>
`
})
export class ModalContentComponent {
public title: string = 'Modal with component';
constructor(public bsModalRef: BsModalRef) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<button type="button" class="btn btn-primary" (click)="openModal(template)">Open first modal</button>

<template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">First modal</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">
This is a first modal
<button type="button" class="btn btn-primary" (click)="openModal2(templateNested)">Open second modal</button>
</div>
</template>

<template #templateNested>
<div class="modal-header">
<h4 class="modal-title pull-left">Second modal</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef2.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
This is nested modal.<br>
<button *ngIf="modalRef" type="button" class="btn btn-danger" (click)="closeFirstModal()">Close first modal</button>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Component, TemplateRef } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';

@Component({
selector: 'demo-modal-service-nested',
templateUrl: './service-nested.html'
})
export class DemoModalServiceNestedComponent {
public modalRef: BsModalRef;
public modalRef2: BsModalRef;
constructor(private modalService: BsModalService) {}

public openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template, {class: 'modal-sm'});
}
public openModal2(template: TemplateRef<any>) {
this.modalRef2 = this.modalService.show(template, {class: 'second'});
}
public closeFirstModal() {
this.modalRef.hide();
this.modalRef = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<button type="button" class="btn btn-primary" (click)="openModal(template)">Open modal</button>
<button type="button" class="btn btn-primary" (click)="openModalWithClass(template)">Open modal with custom css class</button>
<br>
<br>
<button type="button" class="btn btn-primary btn-sm" (click)="config.animated = !config.animated">{{config.animated ? 'Disable' : 'Enable'}} animation</button>
<button type="button" class="btn btn-primary btn-sm" (click)="config.keyboard = !config.keyboard">{{config.keyboard ? 'Disable' : 'Enable'}} Esc</button>
<button type="button" class="btn btn-primary btn-sm" (click)="config.backdrop = !config.backdrop">{{config.backdrop ? 'Disable' : 'Enable'}} backdrop</button>
<button type="button" class="btn btn-primary btn-sm" (click)="config.ignoreBackdropClick = !config.ignoreBackdropClick">{{!config.ignoreBackdropClick ? 'Disable' : 'Enable'}} backdrop click</button>

<template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Modal</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">
Just a modal with a bunch of words inside, nothing serious.
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Component, TemplateRef } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';

@Component({
selector: 'demo-modal-service-options',
templateUrl: './service-options.html'
})
export class DemoModalServiceOptionsComponent {
public modalRef: BsModalRef;
public config = {
animated: true,
keyboard: true,
backdrop: true,
ignoreBackdropClick: false
};
constructor(private modalService: BsModalService) {}

public openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template, this.config);
}

public openModalWithClass(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template, Object.assign({}, this.config, {class: 'gray modal-lg'}));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<button type="button" class="btn btn-primary" (click)="openModal(template)">Create template modal</button>

<template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Modal</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">
This is a modal.
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Component, TemplateRef } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';

@Component({
selector: 'demo-modal-service-static',
templateUrl: './service-template.html'
})
export class DemoModalServiceStaticComponent {
public modalRef: BsModalRef;
constructor(private modalService: BsModalService) {}

public openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
}
2 changes: 1 addition & 1 deletion demo/src/app/components/+modal/demos/static/static.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import {Component} from '@angular/core';

@Component({
selector: 'demo-modal-static',
Expand Down
79 changes: 66 additions & 13 deletions demo/src/app/components/+modal/modal-section.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,104 @@ let titleDoc = require('html-loader!markdown-loader!./docs/title.md');
<h2>Contents</h2>
<ul>
<li><a routerLink="." fragment="usage">Usage</a></li>
<li><a routerLink="." fragment="examples">Examples</a>
<li><a routerLink="." fragment="service-section">Service</a>
<ul>
<li><a routerLink="." fragment="static">Static modal</a></li>
<li><a routerLink="." fragment="sizes">Optional sizes</a></li>
<li><a routerLink="." fragment="child">Child modal</a></li>
<li><a routerLink="." fragment="nested">Nested modals</a></li>
<li><a routerLink="." fragment="events">Modal events</a></li>
<li><a routerLink="." fragment="auto-shown">Auto shown modal</a></li>
<li><a routerLink="." fragment="service-examples">Examples</a>
<ul>
<li><a routerLink="." fragment="service-template">Template</a></li>
<li><a routerLink="." fragment="service-component">Component</a></li>
<li><a routerLink="." fragment="service-nested">Nested</a></li>
<li><a routerLink="." fragment="service-options">Options</a></li>
</ul>
</li>
</ul>
</li>
<li><a routerLink="." fragment="directive-section">Directive</a>
<ul>
<li><a routerLink="." fragment="examples">Examples</a>
<ul>
<li><a routerLink="." fragment="static">Static modal</a></li>
<li><a routerLink="." fragment="sizes">Optional sizes</a></li>
<li><a routerLink="." fragment="child">Child modal</a></li>
<li><a routerLink="." fragment="nested">Nested modals</a></li>
<li><a routerLink="." fragment="events">Modal events</a></li>
<li><a routerLink="." fragment="auto-shown">Auto shown modal</a></li>
</ul>
</li>
</ul>
</li>
<li><a routerLink="." fragment="api-reference">API Reference</a>
<ul>
<li><a routerLink="." fragment="modal-directive">ModalDirective</a></li>
<li><a routerLink="." fragment="modal-backdrop-component">ModalBackdropComponent</a></li>
<li><a routerLink="." fragment="bs-modal-service">BsModalService</a></li>
<li><a routerLink="." fragment="bs-modal-ref">BsModalRef</a></li>
<li><a routerLink="." fragment="modal-options">ModalOptions</a></li>
</ul>
</li>
</ul>
<h2 routerLink="." fragment="usage" id="usage">Usage</h2>
<p [innerHtml]="titleDoc"></p>
<h2 routerLink="." fragment="service-section" id="service-section">Service</h2>
<p>Open a modal from service</p>
<p>To be able to open modals from service, inject BsModalService to your constructor. <br>
Then, call <code>.show()</code> method of modal service. Pass a TemplateRef or a component as a first argument and config as a second (optionally). <br>
<code>.show()</code> method returns an instance of BsModalRef class with <code>.hide()</code> method and <code>content</code> property where you'll find a component which you've passed to service <br>
</p>
<h2 routerLink="." fragment="service-examples" id="service-examples">Examples</h2>
<h3 routerLink="." fragment="service-template" id="service-template">Template</h3>
<ng-sample-box [ts]="demos.serviceTemplate.component" [html]="demos.serviceTemplate.html">
<demo-modal-service-static></demo-modal-service-static>
</ng-sample-box>
<h3 routerLink="." fragment="service-component" id="service-component">Component</h3>
<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>
<ng-sample-box [ts]="demos.serviceComponent.component" [html]="demos.serviceComponent.html">
<demo-modal-service-component></demo-modal-service-component>
</ng-sample-box>
<h3 routerLink="." fragment="service-nested" id="service-nested">Nested</h3>
<p>Nested modals are supported</p>
<ng-sample-box [ts]="demos.serviceNested.component" [html]="demos.serviceNested.html">
<demo-modal-service-nested></demo-modal-service-nested>
</ng-sample-box>
<h3 routerLink="." fragment="service-options" id="service-options">Options</h3>
<p>There are some options that you can configure, like animation, backdrop, closing by Esc button, additional css classes. See the demo below to learn how to configure your modal</p>
<ng-sample-box [ts]="demos.serviceOptions.component" [html]="demos.serviceOptions.html">
<demo-modal-service-options></demo-modal-service-options>
</ng-sample-box>
<h2 routerLink="." fragment="directive-section" id="directive-section">Directive</h2>
<p>Also you can use directive instead of service. See the demos below </p>
<h2 routerLink="." fragment="examples" id="examples">Examples</h2>
<h2 routerLink="." fragment="static" id="static">Static modal</h2>
<h3 routerLink="." fragment="static" id="static">Static modal</h3>
<ng-sample-box [ts]="demos.staticModal.component" [html]="demos.staticModal.html">
<demo-modal-static></demo-modal-static>
</ng-sample-box>
<h2 routerLink="." fragment="sizes" id="sizes">Optional sizes</h2>
<h3 routerLink="." fragment="sizes" id="sizes">Optional sizes</h3>
<ng-sample-box [ts]="demos.sizes.component" [html]="demos.sizes.html">
<demo-modal-sizes></demo-modal-sizes>
</ng-sample-box>
<h2 routerLink="." fragment="child" id="child">Child modal</h2>
<h3 routerLink="." fragment="child" id="child">Child modal</h3>
<p>Control modal from parent component</p>
<ng-sample-box [ts]="demos.child.component" [html]="demos.child.html">
<demo-modal-child></demo-modal-child>
</ng-sample-box>
<h2 routerLink="." fragment="nested" id="nested">Nested modals</h2>
<h3 routerLink="." fragment="nested" id="nested">Nested modals</h3>
<p>Open a modal from another modal</p>
<ng-sample-box [ts]="demos.nested.component" [html]="demos.nested.html">
<demo-modal-nested></demo-modal-nested>
</ng-sample-box>
<h2 routerLink="." fragment="events" id="events">Modal events</h2>
<p>
ModalDirective exposes 4 events: OnShow, OnShown, OnHide, OnHidden. See usage example below. <br>
Expand Down Expand Up @@ -88,6 +139,8 @@ let titleDoc = require('html-loader!markdown-loader!./docs/title.md');
<h2 routerLink="." fragment="api-reference" id="api-reference">API Reference</h2>
<ng-api-doc routerLink="." fragment="modal-directive" id="modal-directive" directive="ModalDirective"></ng-api-doc>
<ng-api-doc routerLink="." fragment="modal-backdrop-component" id="modal-backdrop-component" directive="ModalBackdropComponent"></ng-api-doc>
<ng-api-doc-class routerLink="." fragment="bs-modal-service" id="bs-modal-service" type="BsModalService"></ng-api-doc-class>
<ng-api-doc-class routerLink="." fragment="bs-modal-ref" id="bs-modal-ref" type="BsModalRef"></ng-api-doc-class>
<ng-api-doc-config routerLink="." fragment="modal-options" id="modal-options" type="ModalOptions"></ng-api-doc-config>
</demo-section>`
})
Expand Down
Loading

0 comments on commit 2d02faa

Please sign in to comment.