0
# Dynamic Component Creation
1
2
Core functionality for creating Angular components dynamically at runtime with full lifecycle support, custom injectors, and projected content.
3
4
## Capabilities
5
6
### DynamicComponent
7
8
The main component for dynamically creating other Angular components at runtime.
9
10
```typescript { .api }
11
/**
12
* Main component for dynamically creating other Angular components
13
* Supports full component lifecycle, custom injection, and projected content
14
*/
15
@Component({
16
selector: 'ndc-dynamic',
17
standalone: true,
18
template: '',
19
providers: [
20
{ provide: DynamicComponentInjectorToken, useExisting: DynamicComponent }
21
]
22
})
23
export class DynamicComponent<C = unknown> implements OnChanges, DynamicComponentInjector {
24
/** The component type to create dynamically */
25
@Input() ndcDynamicComponent?: Type<C> | null;
26
27
/** Custom injector for the dynamic component */
28
@Input() ndcDynamicInjector?: Injector | null;
29
30
/** Additional providers for the dynamic component */
31
@Input() ndcDynamicProviders?: StaticProvider[] | null;
32
33
/** Projected content (projectable nodes) for content projection */
34
@Input() ndcDynamicContent?: Node[][];
35
36
/** NgModule reference for the component (for legacy non-standalone components) */
37
@Input() ndcDynamicNgModuleRef?: NgModuleRef<unknown>;
38
39
/** Environment injector for standalone components */
40
@Input() ndcDynamicEnvironmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
41
42
/** Emitted when a component is created */
43
@Output() ndcDynamicCreated: EventEmitter<ComponentRef<C>>;
44
45
/** Reference to the currently created component */
46
componentRef: ComponentRef<C> | null;
47
48
/** Manually trigger component creation */
49
createDynamicComponent(): void;
50
}
51
```
52
53
**Usage Examples:**
54
55
```typescript
56
import { Component, Type, ComponentRef, Injector } from '@angular/core';
57
import { DynamicComponent } from 'ng-dynamic-component';
58
59
// Basic dynamic component creation
60
@Component({
61
selector: 'app-basic-example',
62
template: `
63
<ndc-dynamic
64
[ndcDynamicComponent]="selectedComponent"
65
(ndcDynamicCreated)="onComponentCreated($event)">
66
</ndc-dynamic>
67
`
68
})
69
export class BasicExampleComponent {
70
selectedComponent: Type<any> = MyDynamicComponent;
71
72
onComponentCreated(componentRef: ComponentRef<any>) {
73
// Access the component instance
74
console.log('Component created:', componentRef.instance);
75
76
// Set inputs directly on the component
77
componentRef.instance.title = 'Dynamic Title';
78
79
// Trigger change detection
80
componentRef.changeDetectorRef.detectChanges();
81
}
82
}
83
84
// Advanced usage with custom injector and providers
85
@Component({
86
selector: 'app-advanced-example',
87
template: `
88
<ndc-dynamic
89
[ndcDynamicComponent]="componentType"
90
[ndcDynamicInjector]="customInjector"
91
[ndcDynamicProviders]="providers"
92
[ndcDynamicContent]="projectedContent"
93
(ndcDynamicCreated)="handleCreated($event)">
94
</ndc-dynamic>
95
`
96
})
97
export class AdvancedExampleComponent {
98
componentType = CustomComponent;
99
customInjector?: Injector;
100
providers = [
101
{ provide: 'CONFIG', useValue: { apiUrl: 'https://api.example.com' } },
102
{ provide: MyService, useClass: MyService }
103
];
104
projectedContent?: Node[][];
105
106
constructor(private injector: Injector) {
107
// Create custom injector
108
this.customInjector = Injector.create({
109
providers: [
110
{ provide: 'CUSTOM_TOKEN', useValue: 'custom-value' }
111
],
112
parent: this.injector
113
});
114
}
115
116
handleCreated(componentRef: ComponentRef<CustomComponent>) {
117
// Component is created with custom injection context
118
componentRef.instance.initialize();
119
}
120
}
121
122
// Content projection example
123
@Component({
124
selector: 'app-projection-example',
125
template: `
126
<ndc-dynamic
127
[ndcDynamicComponent]="wrapperComponent"
128
[ndcDynamicContent]="contentNodes">
129
</ndc-dynamic>
130
`
131
})
132
export class ProjectionExampleComponent implements AfterViewInit {
133
wrapperComponent = WrapperComponent;
134
contentNodes?: Node[][];
135
136
@ViewChild('content', { read: ElementRef }) contentEl!: ElementRef;
137
138
ngAfterViewInit() {
139
// Create content to project
140
this.contentNodes = [
141
[this.contentEl.nativeElement.childNodes[0]]
142
];
143
}
144
}
145
```
146
147
### Component Type Switching
148
149
Dynamically switch between different component types:
150
151
```typescript
152
@Component({
153
template: `
154
<button (click)="switchComponent()">Switch Component</button>
155
156
<ndc-dynamic
157
[ndcDynamicComponent]="currentComponent"
158
(ndcDynamicCreated)="onCreated($event)">
159
</ndc-dynamic>
160
`
161
})
162
export class ComponentSwitcherComponent {
163
private components = [ComponentA, ComponentB, ComponentC];
164
private currentIndex = 0;
165
166
get currentComponent() {
167
return this.components[this.currentIndex];
168
}
169
170
switchComponent() {
171
this.currentIndex = (this.currentIndex + 1) % this.components.length;
172
}
173
174
onCreated(componentRef: ComponentRef<any>) {
175
console.log('Switched to:', componentRef.componentType.name);
176
}
177
}
178
```
179
180
### Working with Standalone Components
181
182
For standalone components, use the environment injector:
183
184
```typescript
185
import { EnvironmentInjector } from '@angular/core';
186
187
@Component({
188
template: `
189
<ndc-dynamic
190
[ndcDynamicComponent]="standaloneComponent"
191
[ndcDynamicEnvironmentInjector]="environmentInjector">
192
</ndc-dynamic>
193
`
194
})
195
export class StandaloneExampleComponent {
196
standaloneComponent = MyStandaloneComponent;
197
198
constructor(public environmentInjector: EnvironmentInjector) {}
199
}
200
```
201
202
### Integration with Dynamic I/O
203
204
Combine with dynamic input/output directives for complete functionality:
205
206
```typescript
207
import { DynamicComponent, DynamicIoDirective } from 'ng-dynamic-component';
208
209
@Component({
210
standalone: true,
211
imports: [DynamicComponent, DynamicIoDirective],
212
template: `
213
<ndc-dynamic
214
[ndcDynamicComponent]="component"
215
[ndcDynamicInputs]="inputs"
216
[ndcDynamicOutputs]="outputs"
217
(ndcDynamicCreated)="onCreated($event)">
218
</ndc-dynamic>
219
`
220
})
221
export class FullExampleComponent {
222
component = MyComponent;
223
inputs = { title: 'Hello', data: [1, 2, 3] };
224
outputs = {
225
onSave: (data: any) => console.log('Saved:', data),
226
onDelete: () => console.log('Deleted')
227
};
228
229
onCreated(componentRef: ComponentRef<any>) {
230
// Component is created with inputs/outputs bound
231
}
232
}
233
```
234
235
## Types
236
237
```typescript { .api }
238
/** Interface for objects that can provide ComponentRef access */
239
interface DynamicComponentInjector {
240
componentRef: ComponentRef<unknown> | null;
241
}
242
243
/** Injection token for DynamicComponentInjector */
244
const DynamicComponentInjectorToken: InjectionToken<DynamicComponentInjector>;
245
```