From e3fe9069ae3cd723dbb2235ac707eae2951b27e3 Mon Sep 17 00:00:00 2001 From: Alex Malkevich Date: Wed, 15 Mar 2023 19:42:43 +0100 Subject: [PATCH 1/2] feat(api): add standalone support to components and directives Now it is not required to use `NgModules` with this library --- goldens/ng-dynamic-component/api.md | 27 +++++++++---------- ...omponent-outlet-injector.directive.spec.ts | 9 ++++--- .../component-outlet-injector.directive.ts | 1 + .../component-outlet-injector.module.ts | 4 +-- .../component-outlet-io.directive.spec.ts | 15 +++++------ .../component-outlet-io.directive.ts | 1 + .../dynamic-attributes.directive.spec.ts | 16 +++++------ .../dynamic-attributes.directive.ts | 1 + .../dynamic-attributes.module.ts | 4 +-- .../dynamic-directives.directive.spec.ts | 23 +++++++--------- .../dynamic-directives.directive.ts | 1 + .../dynamic-directives.module.ts | 4 +-- .../dynamic-io/dynamic-io.directive.spec.ts | 24 ++++++++++------- .../lib/dynamic-io/dynamic-io.directive.ts | 1 + .../src/lib/dynamic-io/dynamic-io.module.ts | 3 +-- .../src/lib/dynamic.component.spec.ts | 5 +++- .../src/lib/dynamic.component.ts | 1 + .../src/lib/dynamic.module.ts | 5 ++-- 18 files changed, 70 insertions(+), 75 deletions(-) diff --git a/goldens/ng-dynamic-component/api.md b/goldens/ng-dynamic-component/api.md index 39bd564f3..853ff6a26 100644 --- a/goldens/ng-dynamic-component/api.md +++ b/goldens/ng-dynamic-component/api.md @@ -12,7 +12,6 @@ import { ElementRef } from '@angular/core'; import { EnvironmentInjector } from '@angular/core'; import { EventEmitter } from '@angular/core'; import * as i0 from '@angular/core'; -import * as i3 from '@angular/common'; import { InjectionToken } from '@angular/core'; import { Injector } from '@angular/core'; import { IterableDiffers } from '@angular/core'; @@ -43,7 +42,7 @@ export class ComponentOutletInjectorDirective implements DynamicComponentInjecto // (undocumented) get componentRef(): ComponentRef; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -58,7 +57,7 @@ export class ComponentOutletInjectorModule { // Warning: (ae-forgotten-export) The symbol "i2" needs to be exported by the entry point public-api.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -71,7 +70,7 @@ export class ComponentOutletIoDirective implements DoCheck { // (undocumented) ngDoCheck(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -113,7 +112,7 @@ export class DynamicAttributesDirective implements DoCheck { // (undocumented) setAttribute(name: string, value: string, namespace?: string): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -125,10 +124,10 @@ export class DynamicAttributesModule { // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; // Warning: (ae-forgotten-export) The symbol "i1_4" needs to be exported by the entry point public-api.d.ts - // Warning: (ae-forgotten-export) The symbol "i3_3" needs to be exported by the entry point public-api.d.ts + // Warning: (ae-forgotten-export) The symbol "i2_2" needs to be exported by the entry point public-api.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -155,7 +154,7 @@ export class DynamicComponent implements OnChanges, DynamicComponen // (undocumented) ngOnChanges(changes: SimpleChanges): void; // (undocumented) - static ɵcmp: i0.ɵɵComponentDeclaration, "ndc-dynamic", never, { "ndcDynamicComponent": "ndcDynamicComponent"; "ndcDynamicInjector": "ndcDynamicInjector"; "ndcDynamicProviders": "ndcDynamicProviders"; "ndcDynamicContent": "ndcDynamicContent"; "ndcDynamicNgModuleRef": "ndcDynamicNgModuleRef"; "ndcDynamicEnvironmentInjector": "ndcDynamicEnvironmentInjector"; }, { "ndcDynamicCreated": "ndcDynamicCreated"; }, never, never, false>; + static ɵcmp: i0.ɵɵComponentDeclaration, "ndc-dynamic", never, { "ndcDynamicComponent": "ndcDynamicComponent"; "ndcDynamicInjector": "ndcDynamicInjector"; "ndcDynamicProviders": "ndcDynamicProviders"; "ndcDynamicContent": "ndcDynamicContent"; "ndcDynamicNgModuleRef": "ndcDynamicNgModuleRef"; "ndcDynamicEnvironmentInjector": "ndcDynamicEnvironmentInjector"; }, { "ndcDynamicCreated": "ndcDynamicCreated"; }, never, never, true>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration, never>; } @@ -196,7 +195,7 @@ export class DynamicDirectivesDirective implements OnDestroy, DoCheck { // (undocumented) ngOnDestroy(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -210,7 +209,7 @@ export class DynamicDirectivesModule { // Warning: (ae-forgotten-export) The symbol "i1_5" needs to be exported by the entry point public-api.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -223,7 +222,7 @@ export class DynamicIoDirective implements DoCheck { // (undocumented) ngDoCheck(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -237,7 +236,7 @@ export class DynamicIoModule { // Warning: (ae-forgotten-export) The symbol "i1_3" needs to be exported by the entry point public-api.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -247,10 +246,10 @@ export class DynamicModule { // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; // Warning: (ae-forgotten-export) The symbol "i1_2" needs to be exported by the entry point public-api.d.ts - // Warning: (ae-forgotten-export) The symbol "i3_2" needs to be exported by the entry point public-api.d.ts + // Warning: (ae-forgotten-export) The symbol "i2_3" needs to be exported by the entry point public-api.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public @deprecated (undocumented) diff --git a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.spec.ts b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.spec.ts index fa486016d..83fc645ef 100644 --- a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.spec.ts +++ b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.spec.ts @@ -5,7 +5,7 @@ import { ComponentOutletInjectorDirective } from './component-outlet-injector.di describe('ComponentOutletInjectorDirective', () => { @Component({ selector: 'dynamic', template: '' }) - class DynamicComponent {} + class Dynamic1Component {} @Component({ selector: 'host', @@ -18,9 +18,10 @@ describe('ComponentOutletInjectorDirective', () => { } const testSetup = new TestSetup(HostComponent, { - props: { component: DynamicComponent }, + props: { component: Dynamic1Component }, ngModule: { - declarations: [ComponentOutletInjectorDirective, DynamicComponent], + imports: [ComponentOutletInjectorDirective], + declarations: [Dynamic1Component], }, }); @@ -45,6 +46,6 @@ describe('ComponentOutletInjectorDirective', () => { const directive = fixture.getHost().directive; - expect(directive?.componentRef.instance).toBeInstanceOf(DynamicComponent); + expect(directive?.componentRef.instance).toBeInstanceOf(Dynamic1Component); }); }); diff --git a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.ts b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.ts index 63497d7ea..e203c567d 100644 --- a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.ts +++ b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.directive.ts @@ -13,6 +13,7 @@ import { // eslint-disable-next-line @angular-eslint/directive-selector selector: '[ngComponentOutlet]', exportAs: 'ndcComponentOutletInjector', + standalone: true, providers: [ { provide: DynamicComponentInjectorToken, diff --git a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.module.ts b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.module.ts index b416ab11c..fff8d3d08 100644 --- a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.module.ts +++ b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-injector.module.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ComponentOutletInjectorDirective } from './component-outlet-injector.directive'; @@ -8,8 +7,7 @@ import { ComponentOutletIoDirective } from './component-outlet-io.directive'; * @public */ @NgModule({ - imports: [CommonModule], + imports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], exports: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], - declarations: [ComponentOutletInjectorDirective, ComponentOutletIoDirective], }) export class ComponentOutletInjectorModule {} diff --git a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.spec.ts b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.spec.ts index cf16f679a..5ad2a1718 100644 --- a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.spec.ts +++ b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.spec.ts @@ -6,7 +6,7 @@ import { ComponentOutletIoDirective } from './component-outlet-io.directive'; describe('Directive: ComponentOutletIo', () => { @Component({ selector: 'dynamic', template: 'DynamicComponent' }) - class DynamicComponent { + class Dynamic1Component { @Input() prop1: any; @Input() prop2: any; @Output() output = new EventEmitter(); @@ -21,13 +21,10 @@ describe('Directive: ComponentOutletIo', () => { } const testSetup = new TestSetup(HostComponent, { - props: { component: DynamicComponent }, + props: { component: Dynamic1Component }, ngModule: { - declarations: [ - ComponentOutletIoDirective, - ComponentOutletInjectorDirective, - DynamicComponent, - ], + imports: [ComponentOutletIoDirective, ComponentOutletInjectorDirective], + declarations: [Dynamic1Component], }, }); @@ -40,7 +37,7 @@ describe('Directive: ComponentOutletIo', () => { template: ``, }); - expect(fixture.getComponent(DynamicComponent)).toEqual( + expect(fixture.getComponent(Dynamic1Component)).toEqual( expect.objectContaining({ prop1: '123', prop2: 1, @@ -60,7 +57,7 @@ describe('Directive: ComponentOutletIo', () => { expect(outputs.output).not.toHaveBeenCalled(); - fixture.getComponent(DynamicComponent)!.output.emit('data'); + fixture.getComponent(Dynamic1Component)!.output.emit('data'); expect(outputs.output).toHaveBeenCalledWith('data'); }); diff --git a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.ts b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.ts index f44c3135b..f4804f43e 100644 --- a/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.ts +++ b/projects/ng-dynamic-component/src/lib/component-outlet/component-outlet-io.directive.ts @@ -10,6 +10,7 @@ import { InputsType, IoService, OutputsType } from '../io'; // eslint-disable-next-line @angular-eslint/directive-selector '[ngComponentOutletNdcDynamicInputs],[ngComponentOutletNdcDynamicOutputs]', exportAs: 'ndcDynamicIo', + standalone: true, providers: [IoService], }) export class ComponentOutletIoDirective implements DoCheck { diff --git a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.spec.ts b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.spec.ts index eca204517..e160ec250 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.spec.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.spec.ts @@ -2,7 +2,7 @@ import { Component, Type } from '@angular/core'; import { TestFixture, TestSetup } from '../../test'; import { ComponentOutletInjectorDirective } from '../component-outlet'; -import { DynamicComponent as NdcDynamicComponent } from '../dynamic.component'; +import { DynamicComponent } from '../dynamic.component'; import { AttributesMap, DynamicAttributesDirective, @@ -10,7 +10,7 @@ import { describe('DynamicAttributesDirective', () => { @Component({ selector: 'dynamic', template: `` }) - class DynamicComponent {} + class Dynamic1Component {} @Component({ selector: 'host', @@ -28,17 +28,15 @@ describe('DynamicAttributesDirective', () => { class DynamicTestFixture extends TestFixture { getDynamicElem() { - return this.getComponentElement(DynamicComponent)!; + return this.getComponentElement(Dynamic1Component)!; } } const testSetup = new TestSetup(HostComponent, { - props: { component: DynamicComponent }, + props: { component: Dynamic1Component }, ngModule: { - declarations: [ - DynamicAttributesDirective, - ComponentOutletInjectorDirective, - ], + imports: [DynamicAttributesDirective, ComponentOutletInjectorDirective], + declarations: [Dynamic1Component], }, fixtureCtor: DynamicTestFixture, }); @@ -252,7 +250,7 @@ describe('DynamicAttributesDirective', () => { [ndcDynamicAttributes]="attrs" > `, - ngModule: { declarations: [NdcDynamicComponent] }, + ngModule: { imports: [DynamicComponent] }, }); expect(fixture.getDynamicElem().attributes).toMatchObject({ diff --git a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.ts b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.ts index a846a1ea4..c1edf8947 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.directive.ts @@ -33,6 +33,7 @@ interface AttributeActions { @Directive({ selector: '[ndcDynamicAttributes],[ngComponentOutletNdcDynamicAttributes]', exportAs: 'ndcDynamicAttributes', + standalone: true, }) export class DynamicAttributesDirective implements DoCheck { @Input() diff --git a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.module.ts b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.module.ts index 5f56ed86d..5efee4a75 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.module.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-attributes/dynamic-attributes.module.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ComponentOutletInjectorModule } from '../component-outlet'; @@ -8,8 +7,7 @@ import { DynamicAttributesDirective } from './dynamic-attributes.directive'; * @public */ @NgModule({ - imports: [CommonModule], + imports: [DynamicAttributesDirective], exports: [DynamicAttributesDirective, ComponentOutletInjectorModule], - declarations: [DynamicAttributesDirective], }) export class DynamicAttributesModule {} diff --git a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.spec.ts b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.spec.ts index b04ee6c53..fa327bb22 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.spec.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.spec.ts @@ -23,7 +23,7 @@ import { import { TestFixture, TestSetup } from '../../test'; import { ComponentOutletInjectorDirective } from '../component-outlet'; -import { DynamicComponent as NdcDynamicComponent } from '../dynamic.component'; +import { DynamicComponent } from '../dynamic.component'; import { IoFactoryService } from '../io'; import { DirectiveRef, @@ -34,7 +34,7 @@ import { describe('Directive: DynamicDirectives', () => { @Component({ selector: 'dynamic', template: `` }) - class DynamicComponent {} + class Dynamic1Component {} @Component({ selector: 'host', @@ -121,14 +121,10 @@ describe('Directive: DynamicDirectives', () => { } const testSetup = new TestSetup(HostComponent, { - props: { component: DynamicComponent }, + props: { component: Dynamic1Component }, ngModule: { - declarations: [ - DynamicDirectivesDirective, - ComponentOutletInjectorDirective, - HostComponent, - DynamicComponent, - ], + imports: [DynamicDirectivesDirective, ComponentOutletInjectorDirective], + declarations: [Dynamic1Component], providers: [IoFactoryService], }, fixtureCtor: DirectivesTestFixture, @@ -643,7 +639,7 @@ describe('Directive: DynamicDirectives', () => { ngModule: { imports: [CommonModule] }, }); - const dynamicElem = fixture.getComponentElement(DynamicComponent)!; + const dynamicElem = fixture.getComponentElement(Dynamic1Component)!; expect(dynamicElem).toBeTruthy(); expect(dynamicElem.classes).toEqual({ cls1: true, cls2: true }); @@ -664,7 +660,7 @@ describe('Directive: DynamicDirectives', () => { ngModule: { imports: [CommonModule] }, }); - const dynamicElem = fixture.getComponentElement(DynamicComponent)!; + const dynamicElem = fixture.getComponentElement(Dynamic1Component)!; expect(dynamicElem).toBeTruthy(); expect(dynamicElem.classes).toEqual({ cls1: true, cls2: true }); @@ -684,12 +680,11 @@ describe('Directive: DynamicDirectives', () => { > `, ngModule: { - imports: [CommonModule], - declarations: [NdcDynamicComponent], + imports: [CommonModule, DynamicComponent], }, }); - const dynamicElem = fixture.getComponentElement(DynamicComponent)!; + const dynamicElem = fixture.getComponentElement(Dynamic1Component)!; expect(dynamicElem).toBeTruthy(); expect(dynamicElem.classes).toEqual({ cls1: true, cls2: true }); diff --git a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.ts b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.ts index 687e45337..788db8411 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.directive.ts @@ -70,6 +70,7 @@ export interface DirectiveRef { */ @Directive({ selector: '[ndcDynamicDirectives],[ngComponentOutletNdcDynamicDirectives]', + standalone: true, providers: [IoFactoryService], }) export class DynamicDirectivesDirective implements OnDestroy, DoCheck { diff --git a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.module.ts b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.module.ts index 8295fb0df..02db73397 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.module.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-directives/dynamic-directives.module.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ComponentOutletInjectorModule } from '../component-outlet'; @@ -8,8 +7,7 @@ import { DynamicDirectivesDirective } from './dynamic-directives.directive'; * @public */ @NgModule({ - imports: [CommonModule], + imports: [DynamicDirectivesDirective], exports: [DynamicDirectivesDirective, ComponentOutletInjectorModule], - declarations: [DynamicDirectivesDirective], }) export class DynamicDirectivesModule {} diff --git a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.spec.ts b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.spec.ts index 800c2ab2d..62d54a1b6 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.spec.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.spec.ts @@ -18,7 +18,7 @@ import { TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { TestFixture, TestSetup } from '../../test'; import { ComponentOutletInjectorModule } from '../component-outlet'; -import { DynamicComponent as NdcDynamicComponent } from '../dynamic.component'; +import { DynamicComponent } from '../dynamic.component'; import { InputsType, IoEventArgumentToken, OutputsType } from '../io'; import { IoEventContextProviderToken, @@ -35,7 +35,7 @@ describe('Directive: DynamicIo', () => {

Input3: {{ input3 }}

`, }) - class DynamicComponent implements OnInit, OnChanges { + class Dynamic1Component implements OnInit, OnChanges { @Input() input1: any; @Input() input2: any; @Input('input3Renamed') input3: any; @@ -68,10 +68,10 @@ describe('Directive: DynamicIo', () => { class DynamicTestFixture extends TestFixture { getDynamicComponent() { - return this.getComponent(DynamicComponent)!; + return this.getComponent(Dynamic1Component)!; } getDynamicElement() { - return this.getComponentElement(DynamicComponent)!; + return this.getComponentElement(Dynamic1Component)!; } getDynamicParagraphs() { return this.getDynamicElement()?.queryAll(By.css('p'))!; @@ -79,10 +79,14 @@ describe('Directive: DynamicIo', () => { } const testSetup = new TestSetup(HostComponent, { - props: { component: DynamicComponent }, + props: { component: Dynamic1Component }, ngModule: { - imports: [CommonModule, ComponentOutletInjectorModule], - declarations: [DynamicComponent, DynamicIoDirective], + imports: [ + CommonModule, + ComponentOutletInjectorModule, + DynamicIoDirective, + ], + declarations: [Dynamic1Component], }, fixtureCtor: DynamicTestFixture, }); @@ -207,7 +211,7 @@ describe('Directive: DynamicIo', () => { it('should trigger `ngOnChanges` life-cycle hook if inputs and component updated', async () => { @Component({ selector: 'dynamic2', template: '' }) - class Dynamic2Component extends DynamicComponent {} + class Dynamic2Component extends Dynamic1Component {} const inputs = { input1: 'val1', input2: 'val2' }; @@ -240,7 +244,7 @@ describe('Directive: DynamicIo', () => { }); it('should render inputs with OnPush strategy', async () => { - TestBed.overrideComponent(DynamicComponent, { + TestBed.overrideComponent(Dynamic1Component, { set: { changeDetection: ChangeDetectionStrategy.OnPush }, }); @@ -659,7 +663,7 @@ describe('Directive: DynamicIo', () => { [ndcDynamicInputs]="inputs" > `, - ngModule: { declarations: [NdcDynamicComponent] }, + ngModule: { imports: [DynamicComponent] }, }); expect(fixture.getDynamicComponent()).toEqual( diff --git a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.ts b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.ts index 6c2878ea7..35e2b2201 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.directive.ts @@ -8,6 +8,7 @@ import { InputsType, IoService, OutputsType } from '../io'; @Directive({ selector: '[ndcDynamicInputs],[ndcDynamicOutputs]', exportAs: 'ndcDynamicIo', + standalone: true, providers: [IoService], }) export class DynamicIoDirective implements DoCheck { diff --git a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.module.ts b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.module.ts index a0dbf81cf..e98672495 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.module.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic-io/dynamic-io.module.ts @@ -8,8 +8,7 @@ import { DynamicIoDirective } from './dynamic-io.directive'; * @public */ @NgModule({ - imports: [CommonModule], + imports: [DynamicIoDirective], exports: [DynamicIoDirective, ComponentOutletInjectorModule], - declarations: [DynamicIoDirective], }) export class DynamicIoModule {} diff --git a/projects/ng-dynamic-component/src/lib/dynamic.component.spec.ts b/projects/ng-dynamic-component/src/lib/dynamic.component.spec.ts index b294b5eab..8caaf8559 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic.component.spec.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic.component.spec.ts @@ -57,7 +57,10 @@ describe('DynamicComponent', () => { const testSetup = new TestSetup(HostComponent, { props: { component: InjectedComponent }, - ngModule: { declarations: [DynamicComponent, InjectedComponent] }, + ngModule: { + imports: [DynamicComponent], + declarations: [InjectedComponent], + }, fixtureCtor: InjectedTestFixture, }); diff --git a/projects/ng-dynamic-component/src/lib/dynamic.component.ts b/projects/ng-dynamic-component/src/lib/dynamic.component.ts index fc77cfd50..2fa4e940e 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic.component.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic.component.ts @@ -23,6 +23,7 @@ import { */ @Component({ selector: 'ndc-dynamic', + standalone: true, template: '', providers: [ { provide: DynamicComponentInjectorToken, useExisting: DynamicComponent }, diff --git a/projects/ng-dynamic-component/src/lib/dynamic.module.ts b/projects/ng-dynamic-component/src/lib/dynamic.module.ts index aeaeb133b..7f3efa41e 100644 --- a/projects/ng-dynamic-component/src/lib/dynamic.module.ts +++ b/projects/ng-dynamic-component/src/lib/dynamic.module.ts @@ -8,8 +8,7 @@ import { DynamicComponent } from './dynamic.component'; * @public */ @NgModule({ - imports: [CommonModule, DynamicIoModule], - exports: [DynamicComponent, DynamicIoModule], - declarations: [DynamicComponent], + imports: [DynamicIoModule, DynamicComponent], + exports: [DynamicIoModule, DynamicComponent], }) export class DynamicModule {} From a93bbb5706faa45aedf24c68309318d9c7c29143 Mon Sep 17 00:00:00 2001 From: Alex Malkevich Date: Wed, 15 Mar 2023 20:14:08 +0100 Subject: [PATCH 2/2] docs(readme): add standalone API docs --- README.md | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/README.md b/README.md index 4c22cce4b..ee8e91326 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,33 @@ class MyComponent { } ``` +#### Standalone API + +**Since vv10.7.0** + +You may use `` as a standalone component: + +```ts +import { DynamicComponent } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: ` `, + imports: [DynamicComponent], + standalone: true, +}) +class MyComponent { + component = Math.random() > 0.5 ? MyDynamicComponent1 : MyDynamicComponent2; +} +``` + +_NOTE:_ Hovewer you should be aware that this will only import `` +into your component and nothing else so things like dynamic inputs/outputs +will not work and you will have to import them separately (see their respective sections). + +If you still need to use both `` and dynamic inputs/outputs it is recommended +to keep using `DynamicModule` API. + ### NgComponentOutlet You can also use [`NgComponentOutlet`](https://angular.io/api/common/NgComponentOutlet) @@ -121,6 +148,53 @@ class MyComponent { } ``` +#### Standalone API + +**Since vv10.7.0** + +You may use dynamic inputs/outputs with `*ngComponentOutlet` as a standalone API: + +```ts +import { ComponentOutletInjectorModule } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: `` + imports: [ComponentOutletInjectorModule], + standalone: true, +}) +class MyComponent { + component = MyDynamicComponent1; + inputs = {...}; + outputs = {...}; +} +``` + +If you want to use standard dynamic inputs/outputs with `ngComponentOutlet` as a standalone API +you need to add the `DynamicIoDirective` to your imports: + +```ts +import { DynamicIoDirective, ComponentOutletInjectorModule } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: `` + imports: [DynamicIoDirective, ComponentOutletInjectorModule], + standalone: true, +}) +class MyComponent { + component = MyDynamicComponent1; + inputs = {...}; + outputs = {...}; +} +``` + ### Inputs and Outputs You can pass `inputs` and `outputs` to your dynamic components: @@ -166,6 +240,34 @@ class MyDynamicComponent1 { Here you can update your inputs (ex. `inputs.hello = 'WORLD'`) and they will trigger standard Angular's life-cycle hooks (of course you should consider which change detection strategy you are using). +#### Standalone API + +**Since vv10.7.0** + +You can use standalone API to pass dynamic inputs/outputs +using `DynamicIoDirective` with `DynamicComponent` or `ngComponentOutlet`: + +```ts +import { DynamicIoDirective, DynamicComponent } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: ` + + `, + imports: [DynamicIoDirective, DynamicComponent] +}) +class MyComponent { + component = MyDynamicComponent1; + inputs = {...}; + outputs = {...}; +} +``` + #### Output template variables **Since v6.1.0** @@ -317,6 +419,32 @@ class MyComponent { } ``` +#### Standalone API + +**Since vv10.7.0** + +You can use standalone API to pass dynamic inputs/outputs +using `DynamicAttributesDirective` with `DynamicComponent` or `ngComponentOutlet`: + +```ts +import { DynamicAttributesDirective, DynamicComponent } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: ` + + `, + imports: [DynamicAttributesDirective, DynamicComponent] +}) +class MyComponent { + component = MyDynamicComponent1; + attrs: AttributesMap = {...}; +} +``` + ### Directives (experimental) **Since v3.1.0** you can now declaratively set directives, via `ndcDynamicDirectives`. @@ -412,6 +540,32 @@ class MyComponent { } ``` +#### Standalone API + +**Since vv10.7.0** + +You can use standalone API to pass dynamic inputs/outputs +using `DynamicDirectivesDirective` with `DynamicComponent` or `ngComponentOutlet`: + +```ts +import { DynamicDirectivesDirective, DynamicComponent } from 'ng-dynamic-component'; + +@Component({ + selector: 'my-component', + template: ` + + `, + imports: [DynamicDirectivesDirective, DynamicComponent] +}) +class MyComponent { + component = MyDynamicComponent1; + dirs = [...]; +} +``` + ### Extra You can have more advanced stuff over your dynamically rendered components like setting custom injector (`[ndcDynamicInjector]`) @@ -421,6 +575,8 @@ or projecting nodes (`[ndcDynamicContent]`). **Since v10.6.0**: You can provide custom NgModuleRef (`[ndcDynamicNgModuleRef]`) or EnvironmentInjector (`[ndcDynamicEnvironmentInjector]`) for your dynamic component. +--- + NOTE: In practice functionality of this library is split in two pieces: - one - component (`ndc-dynamic`) that is responsible for instantiating and rendering of dynamic components;