From 5503e68118f71915f17c8b03fa17dc1d3070e8b4 Mon Sep 17 00:00:00 2001 From: gund Date: Sun, 31 Dec 2017 01:21:08 +0400 Subject: [PATCH] feat(preset): Implement basic preset module --- src/preset/index.ts | 4 +++ src/preset/preset-default.module.ts | 15 +++++++++ src/preset/preset-method.ts | 15 +++++++++ src/preset/preset-token.ts | 6 ++++ src/preset/preset.module.ts | 9 ++++-- src/preset/preset.service.spec.ts | 21 +++++++++++++ src/preset/preset.service.ts | 48 +++++++++++++++++++++++++++++ 7 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/preset/preset-default.module.ts create mode 100644 src/preset/preset-method.ts create mode 100644 src/preset/preset-token.ts create mode 100644 src/preset/preset.service.spec.ts create mode 100644 src/preset/preset.service.ts diff --git a/src/preset/index.ts b/src/preset/index.ts index 1ffc68b..70c1977 100644 --- a/src/preset/index.ts +++ b/src/preset/index.ts @@ -1 +1,5 @@ +export { PresetType } from './preset-token'; +export * from './preset-method'; +export * from './preset.service'; export * from './preset.module'; +export * from './preset-default.module'; diff --git a/src/preset/preset-default.module.ts b/src/preset/preset-default.module.ts new file mode 100644 index 0000000..3a6d960 --- /dev/null +++ b/src/preset/preset-default.module.ts @@ -0,0 +1,15 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { createWithPresetMethodFor } from './preset-method'; +import { PresetService } from './preset.service'; + +@NgModule({ + imports: [CommonModule], + exports: [], + declarations: [], + providers: [PresetService], +}) +export class PresetDefaultModule { + static withPreset = createWithPresetMethodFor(PresetDefaultModule); +} diff --git a/src/preset/preset-method.ts b/src/preset/preset-method.ts new file mode 100644 index 0000000..539ef12 --- /dev/null +++ b/src/preset/preset-method.ts @@ -0,0 +1,15 @@ +import { ANALYZE_FOR_ENTRY_COMPONENTS, ModuleWithProviders, Type } from '@angular/core'; + +import { PRESET_TYPES_TOKEN, PresetType } from './preset-token'; + +export function createWithPresetMethodFor(moduleClass: Type) { + return (presetType: PresetType): ModuleWithProviders => { + return { + ngModule: moduleClass, + providers: [ + { provide: PRESET_TYPES_TOKEN, useValue: presetType, multi: true }, + { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: presetType, multi: true }, + ], + }; + }; +} diff --git a/src/preset/preset-token.ts b/src/preset/preset-token.ts new file mode 100644 index 0000000..967b3ea --- /dev/null +++ b/src/preset/preset-token.ts @@ -0,0 +1,6 @@ +import { InjectionToken, Type } from '@angular/core'; + +// tslint:disable-next-line:no-empty-interface +export interface PresetType extends Type { } + +export const PRESET_TYPES_TOKEN = new InjectionToken('PresetTypes'); diff --git a/src/preset/preset.module.ts b/src/preset/preset.module.ts index 3ce8bf0..5ebf237 100644 --- a/src/preset/preset.module.ts +++ b/src/preset/preset.module.ts @@ -1,9 +1,12 @@ +import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { PresetService } from './preset.service'; + @NgModule({ - imports: [], + imports: [CommonModule], exports: [], declarations: [], - providers: [], + providers: [PresetService], }) -export class PresetModule {} +export class PresetModule { } diff --git a/src/preset/preset.service.spec.ts b/src/preset/preset.service.spec.ts new file mode 100644 index 0000000..11e4e73 --- /dev/null +++ b/src/preset/preset.service.spec.ts @@ -0,0 +1,21 @@ +import { inject, TestBed } from '@angular/core/testing'; + +import { PRESET_TYPES_TOKEN } from './preset-token'; +import { PresetService } from './preset.service'; + +class MockPreset { } + +describe('Service: Preset', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: PRESET_TYPES_TOKEN, useValue: MockPreset, multi: true }, + PresetService, + ] + }); + }); + + it('should ...', inject([PresetService], (service: PresetService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/preset/preset.service.ts b/src/preset/preset.service.ts new file mode 100644 index 0000000..248085c --- /dev/null +++ b/src/preset/preset.service.ts @@ -0,0 +1,48 @@ +import { ComponentFactoryResolver, ComponentRef, Injectable, Injector, OnDestroy } from '@angular/core'; + +import { PRESET_TYPES_TOKEN, PresetType } from './preset-token'; + +@Injectable() +export class PresetService implements OnDestroy { + + private presetTypes = this.injector.get(PRESET_TYPES_TOKEN); + private presetCompRefs: ComponentRef[] = []; + private finalPresetComp: any; + + constructor( + private injector: Injector, + private compResolver: ComponentFactoryResolver, + ) { } + + getPreset(): T { + if (this.presetTypes.length && !this.presetCompRefs.length) { + this.presetCompRefs = this.presetTypes + .map(presetType => this.createCompFromType(presetType)); + } + + if (!this.finalPresetComp) { + this.finalPresetComp = this.mergeCompRefs(this.presetCompRefs); + } + + return this.finalPresetComp; + } + + /** @internal */ + ngOnDestroy() { + this.presetCompRefs + .forEach(presetCompRef => presetCompRef.destroy()); + this.presetCompRefs = []; + } + + private createCompFromType(type: PresetType) { + return this.compResolver + .resolveComponentFactory(type) + .create(this.injector); + } + + private mergeCompRefs(compRefs: ComponentRef[]): T { + return compRefs.reduce((comp, compRef) => + Object.assign(comp, compRef.instance), {} as T); + } + +}