From 146c8631606a0f0b45547a996ce2a36c032907c5 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 11 Apr 2020 00:33:49 +0300 Subject: [PATCH] feat: add a service that projects to modal container --- .../theme-shared/src/lib/services/index.ts | 1 + .../src/lib/services/modal.service.ts | 47 ++++++++++ .../src/lib/tests/modal.service.spec.ts | 87 +++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/services/modal.service.ts create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/tests/modal.service.spec.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts index c53455a433..c363a56894 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/index.ts @@ -1,2 +1,3 @@ export * from './confirmation.service'; +export * from './modal.service'; export * from './toaster.service'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/modal.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/modal.service.ts new file mode 100644 index 0000000000..ac481f68ea --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/modal.service.ts @@ -0,0 +1,47 @@ +import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core'; +import { ComponentRef, Injectable, TemplateRef, ViewContainerRef } from '@angular/core'; +import { ModalContainerComponent } from '../components/modal/modal-container.component'; + +@Injectable({ + providedIn: 'root', +}) +export class ModalService { + private containerComponentRef: ComponentRef; + + constructor(private contentProjectionService: ContentProjectionService) { + this.setContainer(); + } + + private setContainer() { + this.containerComponentRef = this.contentProjectionService.projectContent( + PROJECTION_STRATEGY.AppendComponentToBody(ModalContainerComponent), + ); + + this.containerComponentRef.changeDetectorRef.detectChanges(); + } + + clearModal() { + this.getContainer().clear(); + this.detectChanges(); + } + + detectChanges() { + this.containerComponentRef.changeDetectorRef.detectChanges(); + } + + getContainer(): ViewContainerRef { + return this.containerComponentRef.instance.container; + } + + renderTemplate(template: TemplateRef, context?: T) { + const containerRef = this.getContainer(); + + const strategy = PROJECTION_STRATEGY.ProjectTemplateToContainer( + template, + containerRef, + context, + ); + + this.contentProjectionService.projectContent(strategy); + } +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.service.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.service.spec.ts new file mode 100644 index 0000000000..e1a2e8bf51 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/modal.service.spec.ts @@ -0,0 +1,87 @@ +import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; +import { ModalContainerComponent } from '../components/modal/modal-container.component'; +import { ModalService } from '../services'; + +describe('ModalContainerComponent', () => { + @Component({ + template: ` + +
bar
+
+ `, + }) + class TestComponent { + @ViewChild('ref', { static: true }) + template: TemplateRef; + + constructor(public service: ModalService) {} + } + + let spectator: Spectator; + let service: ModalService; + + const createComponent = createComponentFactory({ + component: TestComponent, + entryComponents: [ModalContainerComponent], + }); + + beforeEach(() => { + spectator = createComponent(); + service = spectator.component.service; + }); + + afterEach(() => { + service.getContainer().clear(); + service['containerComponentRef'].changeDetectorRef.detectChanges(); + service['containerComponentRef'].destroy(); + }); + + describe('#getContainer', () => { + it('should return the ViewContainerRef of ModalContainerComponent', () => { + let foo = document.querySelector('div.foo'); + expect(foo).toBeNull(); + + const containerRef = service.getContainer(); + const embeddedViewRef = containerRef.createEmbeddedView(spectator.component.template); + + foo = document.querySelector('div.foo'); + expect(foo).toBe(embeddedViewRef.rootNodes[0]); + expect(foo.textContent).toBe('bar'); + }); + }); + + describe('#renderTemplate', () => { + it('should render given template using the ViewContainerRef of ModalContainerComponent', () => { + let foo = document.querySelector('div.foo'); + expect(foo).toBeNull(); + + service.renderTemplate(spectator.component.template); + + foo = document.querySelector('div.foo'); + expect(foo.textContent).toBe('bar'); + }); + }); + + describe('#detectChanges', () => { + it('should call detectChanges on the containerComponentRef', () => { + const spy = jest.spyOn(service['containerComponentRef'].changeDetectorRef, 'detectChanges'); + + service.detectChanges(); + + expect(spy).toHaveBeenCalledTimes(1); + }); + }); + + describe('#clearModal', () => { + it('should call clear on the ViewContainerRef and detectChanges', () => { + const clear = jest.spyOn(service.getContainer(), 'clear'); + const detectChanges = jest.spyOn(service, 'detectChanges'); + + service.clearModal(); + + expect(clear).toHaveBeenCalledTimes(1); + expect(detectChanges).toHaveBeenCalledTimes(1); + }); + }); +});