Skip to content

Commit bfaceb3

Browse files
msgoloborodovMihail Goloborodovgund
authored
feat: add NgModuleRef and EnvironmentInjector inputs to ndc-dynamic component
* Add `ndcDynamicNgModuleRef` input to `ndc-dynamic` component * Add `ndcDynamicEnvironmentInjector` input to `ndc-dynamic` component Co-authored-by: Mihail Goloborodov <[email protected]> Co-authored-by: Alex Malkevich <[email protected]>
1 parent 5df76ff commit bfaceb3

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ You can have more advanced stuff over your dynamically rendered components like
418418
or providing additional/overriding providers (`[ndcDynamicProviders]`) or both simultaneously
419419
or projecting nodes (`[ndcDynamicContent]`).
420420

421+
**Since v10.6.0**: You can provide custom NgModuleRef (`[ndcDynamicNgModuleRef]`)
422+
or EnvironmentInjector (`[ndcDynamicEnvironmentInjector]`) for your dynamic component.
423+
421424
NOTE: In practice functionality of this library is split in two pieces:
422425

423426
- one - component (`ndc-dynamic`) that is responsible for instantiating and rendering of dynamic components;

projects/ng-dynamic-component/src/lib/dynamic.component.spec.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
/* eslint-disable @angular-eslint/component-selector */
22
import {
33
Component,
4+
createNgModule,
5+
EnvironmentInjector,
46
InjectionToken,
57
Injector,
8+
NgModule,
9+
NgModuleRef,
610
StaticProvider,
711
Type,
812
} from '@angular/core';
@@ -21,6 +25,8 @@ describe('DynamicComponent', () => {
2125
[ndcDynamicInjector]="injector"
2226
[ndcDynamicProviders]="providers"
2327
[ndcDynamicContent]="content"
28+
[ndcDynamicNgModuleRef]="ngModuleRef"
29+
[ndcDynamicEnvironmentInjector]="environmentInjector"
2430
(ndcDynamicCreated)="createdComponent($event)"
2531
></ndc-dynamic>`,
2632
})
@@ -29,6 +35,8 @@ describe('DynamicComponent', () => {
2935
injector?: Injector;
3036
providers?: StaticProvider[];
3137
content?: Node[][];
38+
ngModuleRef?: NgModuleRef<unknown>;
39+
environmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
3240
createdComponent = jest.fn();
3341
}
3442

@@ -258,4 +266,104 @@ describe('DynamicComponent', () => {
258266
);
259267
});
260268
});
269+
270+
describe('@Input(ndcDynamicNgModuleRef)', () => {
271+
const testToken = new InjectionToken<any>('TEST_TOKEN');
272+
const testTokenValue = {};
273+
let ngModuleRef: NgModuleRef<any>;
274+
let parentInjector: Injector;
275+
276+
@NgModule({
277+
providers: [{ provide: testToken, useValue: testTokenValue }],
278+
})
279+
class CustomNgModule {}
280+
281+
it('should use input if provided for ngModuleRef', async () => {
282+
const fixture = await testSetup.redner();
283+
284+
parentInjector = TestBed.inject(NgModuleRef).injector;
285+
ngModuleRef = createNgModule(CustomNgModule, parentInjector);
286+
fixture.setHostProps({ ngModuleRef });
287+
288+
expect(fixture.getInjectedInjector().get(testToken)).toBe(testTokenValue);
289+
});
290+
291+
it('should change component if input updated', async () => {
292+
const fixture = await testSetup.redner();
293+
294+
parentInjector = TestBed.inject(NgModuleRef).injector;
295+
ngModuleRef = createNgModule(CustomNgModule, parentInjector);
296+
fixture.setHostProps({ ngModuleRef });
297+
298+
const injectedComp = fixture.getInjectedComponent();
299+
300+
expect(fixture.getInjectedInjector().get(testToken)).toBe(testTokenValue);
301+
302+
const testTokenValue2 = {};
303+
@NgModule({
304+
providers: [{ provide: testToken, useValue: testTokenValue2 }],
305+
})
306+
class CustomNgModule2 {}
307+
ngModuleRef = createNgModule(CustomNgModule2, parentInjector);
308+
309+
fixture.setHostProps({ ngModuleRef });
310+
311+
expect(fixture.getInjectedInjector().get(testToken)).toBe(
312+
testTokenValue2,
313+
);
314+
expect(fixture.getInjectedComponent()).not.toBe(injectedComp);
315+
});
316+
});
317+
318+
describe('@Input(ndcDynamicEnvironmentInjector)', () => {
319+
const testToken = new InjectionToken<any>('TEST_TOKEN');
320+
const testTokenValue = {};
321+
let ngModuleRef: NgModuleRef<any>;
322+
let environmentInjector: EnvironmentInjector;
323+
let parentInjector: Injector;
324+
325+
@NgModule({
326+
providers: [{ provide: testToken, useValue: testTokenValue }],
327+
})
328+
class CustomNgModule {}
329+
330+
it('should use input if provided for environmentInjector', async () => {
331+
const fixture = await testSetup.redner();
332+
333+
parentInjector = TestBed.inject(NgModuleRef).injector;
334+
ngModuleRef = createNgModule(CustomNgModule, parentInjector);
335+
environmentInjector = ngModuleRef.injector;
336+
fixture.setHostProps({ environmentInjector });
337+
338+
expect(fixture.getInjectedInjector().get(testToken)).toBe(testTokenValue);
339+
});
340+
341+
it('should change component if input updated', async () => {
342+
const fixture = await testSetup.redner();
343+
344+
parentInjector = TestBed.inject(NgModuleRef).injector;
345+
ngModuleRef = createNgModule(CustomNgModule, parentInjector);
346+
environmentInjector = ngModuleRef.injector;
347+
fixture.setHostProps({ environmentInjector });
348+
349+
const injectedComp = fixture.getInjectedComponent();
350+
351+
expect(fixture.getInjectedInjector().get(testToken)).toBe(testTokenValue);
352+
353+
const testTokenValue2 = {};
354+
@NgModule({
355+
providers: [{ provide: testToken, useValue: testTokenValue2 }],
356+
})
357+
class CustomNgModule2 {}
358+
ngModuleRef = createNgModule(CustomNgModule2, parentInjector);
359+
environmentInjector = ngModuleRef.injector;
360+
361+
fixture.setHostProps({ environmentInjector });
362+
363+
expect(fixture.getInjectedInjector().get(testToken)).toBe(
364+
testTokenValue2,
365+
);
366+
expect(fixture.getInjectedComponent()).not.toBe(injectedComp);
367+
});
368+
});
261369
});

projects/ng-dynamic-component/src/lib/dynamic.component.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {
22
Component,
33
ComponentRef,
4+
EnvironmentInjector,
45
EventEmitter,
56
Injector,
67
Input,
8+
NgModuleRef,
79
OnChanges,
810
Output,
911
SimpleChanges,
@@ -31,6 +33,8 @@ export class DynamicComponent<C = unknown>
3133
'ndcDynamicInjector',
3234
'ndcDynamicProviders',
3335
'ndcDynamicContent',
36+
'ndcDynamicNgModuleRef',
37+
'ndcDynamicEnvironmentInjector',
3438
];
3539

3640
@Input()
@@ -41,6 +45,10 @@ export class DynamicComponent<C = unknown>
4145
ndcDynamicProviders?: StaticProvider[] | null;
4246
@Input()
4347
ndcDynamicContent?: Node[][];
48+
@Input()
49+
ndcDynamicNgModuleRef?: NgModuleRef<unknown>;
50+
@Input()
51+
ndcDynamicEnvironmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
4452

4553
@Output()
4654
ndcDynamicCreated = new EventEmitter<ComponentRef<C>>();
@@ -68,6 +76,8 @@ export class DynamicComponent<C = unknown>
6876
index: 0,
6977
injector: this._resolveInjector(),
7078
projectableNodes: this.ndcDynamicContent,
79+
ngModuleRef: this.ndcDynamicNgModuleRef,
80+
environmentInjector: this.ndcDynamicEnvironmentInjector,
7181
});
7282
this.ndcDynamicCreated.emit(this.componentRef);
7383
}

0 commit comments

Comments
 (0)