From e0a42daf0b5881cb08c42524405508b78ebab54f Mon Sep 17 00:00:00 2001 From: evan-qualls <130243196+evan-qualls@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:04:59 -0500 Subject: [PATCH 1/3] Add files via upload feat(modal): Add container property to ModalOptions These changes will allow developers to optionally place render modals within the application context, allowing components injected via BsModalService to use ViewEncapsulation and support change detection. * Added container property to ModalOptions. * Updated modalConfigDefaults with "container: 'body' " to prevent breaking changes/behavior * Updated BsModalService and Modal-Directive so that the container element is no longer hard-coded to 'body' but rather config.container --- src/modal/bs-modal.service.ts | 4 ++-- src/modal/modal-options.class.ts | 7 ++++++- src/modal/modal.directive.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modal/bs-modal.service.ts b/src/modal/bs-modal.service.ts index a5a253b24a..71da52fc18 100644 --- a/src/modal/bs-modal.service.ts +++ b/src/modal/bs-modal.service.ts @@ -110,7 +110,7 @@ export class BsModalService { if (isBackdropEnabled && isBackdropInDOM) { this._backdropLoader .attach(ModalBackdropComponent) - .to('body') + .to(this.config.container) .show({ isAnimated: this.config.animated }); this.backdropRef = this._backdropLoader._componentRef; } @@ -140,7 +140,7 @@ export class BsModalService { .provide({ provide: ModalOptions, useValue: this.config }) .provide({ provide: BsModalRef, useValue: bsModalRef }) .attach(ModalContainerComponent) - .to('body'); + .to(this.config.container); bsModalRef.hide = () => this.hide(bsModalRef.id); bsModalRef.setClass = (newClass: string) => { if (modalContainerRef.instance) { diff --git a/src/modal/modal-options.class.ts b/src/modal/modal-options.class.ts index 37ff61e066..392edf6b86 100644 --- a/src/modal/modal-options.class.ts +++ b/src/modal/modal-options.class.ts @@ -1,4 +1,4 @@ -import { Injectable, StaticProvider, InjectionToken } from '@angular/core'; +import { ElementRef, Injectable, StaticProvider, InjectionToken } from '@angular/core'; import { ClassName, CloseInterceptorFn, DismissReasons, Selector, TransitionDurations } from './models'; @Injectable({providedIn: 'platform'}) @@ -30,6 +30,10 @@ export class ModalOptions> { * Css class for opened modal */ class?: string; + /** + * CSS selector or ElementRef to which the modal is appended + */ + container?: string | ElementRef; /** * Toggle animation */ @@ -63,6 +67,7 @@ export const modalConfigDefaults: ModalOptions = { show: false, ignoreBackdropClick: false, class: '', + container: 'body', animated: true, initialState: {}, closeInterceptor: void 0 diff --git a/src/modal/modal.directive.ts b/src/modal/modal.directive.ts index 0d72bccf62..4393a4302b 100644 --- a/src/modal/modal.directive.ts +++ b/src/modal/modal.directive.ts @@ -337,7 +337,7 @@ export class ModalDirective implements OnDestroy, OnInit { this.removeBackdrop(); this._backdrop .attach(ModalBackdropComponent) - .to('body') + .to(this._config.container) .show({ isAnimated: this._config.animated }); this.backdrop = this._backdrop._componentRef; From 3ef03468b3824320bd10b87279e8d250af256cd8 Mon Sep 17 00:00:00 2001 From: Evan Qualls Date: Sat, 8 Apr 2023 20:37:47 -0500 Subject: [PATCH 2/3] feat(modal): Add container property to ModalOptions Updated documentation pages Updated test case for ModalOptions.container property --- apps/ngx-bootstrap-docs/src/ng-api-doc.ts | 5 +++++ .../examples.component.html | 2 +- .../lib/models/components-examples.model.ts | 2 +- .../service-component/service-component.css | 4 ++++ .../service-component/service-component.ts | 17 +++++++++++----- .../modal/src/lib/modal-section.list.ts | 1 + src/modal/testing/modal.service.spec.ts | 20 ++++++++++++++++++- 7 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 libs/doc-pages/modal/src/lib/demos/service-component/service-component.css diff --git a/apps/ngx-bootstrap-docs/src/ng-api-doc.ts b/apps/ngx-bootstrap-docs/src/ng-api-doc.ts index 522c20721e..2b91dd22ed 100644 --- a/apps/ngx-bootstrap-docs/src/ng-api-doc.ts +++ b/apps/ngx-bootstrap-docs/src/ng-api-doc.ts @@ -2746,6 +2746,11 @@ export const ngdoc: any = { "type": "string", "description": "

Css class for opened modal

\n" }, + { + "name": "container", + "type": "string | ElementRef", + "description": "

The CSS Selector or ElementRef for where the modal window will be injected into the page.

\n" + }, { "name": "closeInterceptor", "type": "CloseInterceptorFn", diff --git a/libs/common-docs/src/lib/demo-section-components/demo-examples-section/examples.component.html b/libs/common-docs/src/lib/demo-section-components/demo-examples-section/examples.component.html index c64b2088c9..64b4326c36 100644 --- a/libs/common-docs/src/lib/demo-section-components/demo-examples-section/examples.component.html +++ b/libs/common-docs/src/lib/demo-section-components/demo-examples-section/examples.component.html @@ -19,7 +19,7 @@

- + diff --git a/libs/common-docs/src/lib/models/components-examples.model.ts b/libs/common-docs/src/lib/models/components-examples.model.ts index c57c489275..0e53cbd6b5 100644 --- a/libs/common-docs/src/lib/models/components-examples.model.ts +++ b/libs/common-docs/src/lib/models/components-examples.model.ts @@ -6,7 +6,7 @@ export interface ComponentExample { description?: string; component?: SourceCodeModel; html?: SourceCodeModel; - style?: string; + style?: SourceCodeModel; css?: string; outlet?: any; // ToDo: Component } diff --git a/libs/doc-pages/modal/src/lib/demos/service-component/service-component.css b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.css new file mode 100644 index 0000000000..69ef488b1c --- /dev/null +++ b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.css @@ -0,0 +1,4 @@ +.profit { + color: green; + font-weight: 700; +} diff --git a/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts index a4ffe465fe..1be9ba3a4f 100644 --- a/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts +++ b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts @@ -12,12 +12,14 @@ export class DemoModalServiceFromComponent { openModalWithComponent() { const initialState: ModalOptions = { + container: 'bs-demo', initialState: { list: [ 'Open a modal with component', 'Pass your data', 'Do something else', - '...' + '...', + 'Push button to find out!' ], title: 'Modal with component' } @@ -32,6 +34,7 @@ export class DemoModalServiceFromComponent { @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'modal-content', + styleUrls: ['./service-component.css'], template: ` ` }) -export class ModalContentComponent implements OnInit { +export class ModalContentComponent { title?: string; + profitBtnPressed: boolean = false; closeBtnName?: string; list: any[] = []; constructor(public bsModalRef: BsModalRef) {} - ngOnInit() { - this.list.push('PROFIT!!!'); + showProfit() { + this.profitBtnPressed = true; + this.list[this.list.length - 1] = 'PROFIT!!!'; } + } diff --git a/libs/doc-pages/modal/src/lib/modal-section.list.ts b/libs/doc-pages/modal/src/lib/modal-section.list.ts index 86d61b8526..2311a1e6cd 100644 --- a/libs/doc-pages/modal/src/lib/modal-section.list.ts +++ b/libs/doc-pages/modal/src/lib/modal-section.list.ts @@ -60,6 +60,7 @@ export const demoComponentContent: ContentSection[] = [ anchor: 'service-component', component: require('!!raw-loader!./demos/service-component/service-component.ts'), html: require('!!raw-loader!./demos/service-component/service-component.html'), + style: require('!!raw-loader!./demos/service-component/service-component.css'), description: `

Creating a modal with component just as easy as it is with template. Just pass your component in .show() method as in example, and don't forget to include your component to entryComponents of your NgModule
If you passed a component diff --git a/src/modal/testing/modal.service.spec.ts b/src/modal/testing/modal.service.spec.ts index 9c0c6a7409..522b5e8e8e 100644 --- a/src/modal/testing/modal.service.spec.ts +++ b/src/modal/testing/modal.service.spec.ts @@ -4,7 +4,9 @@ import { pairwise, tap } from 'rxjs/operators'; import { BsModalService, ModalModule } from '../index'; -@Component({ template: '

Dummy Component
' }) +@Component({ + selector: 'dummy-component', + template: '
Dummy Component
' }) class DummyComponent { // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars constructor(modalService: BsModalService) { } @@ -130,4 +132,20 @@ describe('Modal service', () => { jest.runAllTimers(); expect(onHiddenSpy).toHaveBeenCalledWith({ id }); }); + + it('should render in element by default', done => { + modalService.onShown.subscribe((data) => { + expect(document.querySelector('dummy-component modal-container')).toBeDefined(); + done(); + }) + modalService.show(TestModalComponent); + }) + + it('should render in the container selector provided', done => { + modalService.onShown.subscribe((data) => { + expect(document.querySelector('dummy-component modal-container')).toBeDefined(); + done(); + }) + modalService.show(TestModalComponent, { container: 'dummy-component'}); + }) }); From fc74b30734b3def088d50f3a9070983ceed851e5 Mon Sep 17 00:00:00 2001 From: Evan Qualls Date: Sat, 8 Apr 2023 20:59:10 -0500 Subject: [PATCH 3/3] feat(modal): Add container property to ModalOptions These changes will allow developers to optionally place render modals within the application context, allowing components injected via BsModalService to use ViewEncapsulation and support change detection. * Added container property to ModalOptions. * Updated modalConfigDefaults with "container: 'body' " to prevent breaking changes/behavior * Updated BsModalService and Modal-Directive so that the container element is no longer hard-coded to 'body' but rather config.container --- .../modal/src/lib/demos/service-component/service-component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts index 1be9ba3a4f..4eb138385c 100644 --- a/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts +++ b/libs/doc-pages/modal/src/lib/demos/service-component/service-component.ts @@ -66,5 +66,4 @@ export class ModalContentComponent { this.profitBtnPressed = true; this.list[this.list.length - 1] = 'PROFIT!!!'; } - }