Skip to content

Commit f9e9fc4

Browse files
SkyZeroZxkirjs
authored andcommitted
docs: enhance programmatic rendering guide by covering ngComponentOutlet options
1 parent d129d20 commit f9e9fc4

1 file changed

Lines changed: 153 additions & 0 deletions

File tree

adev/src/content/guide/components/programmatic-rendering.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,159 @@ export class CustomDialog {
4141
}
4242
```
4343

44+
### Passing inputs to dynamically rendered components
45+
46+
You can pass inputs to the dynamically rendered component using the `ngComponentOutletInputs` property. This property accepts an object where keys are input names and values are the input values.
47+
48+
```angular-ts
49+
@Component({
50+
selector: 'user-greeting',
51+
template: `
52+
<div>
53+
<p>User: {{ username() }}</p>
54+
<p>Role: {{ role() }}</p>
55+
</div>
56+
`,
57+
})
58+
export class UserGreeting {
59+
username = input.required<string>();
60+
role = input('guest');
61+
}
62+
63+
@Component({
64+
selector: 'profile-view',
65+
imports: [NgComponentOutlet],
66+
template: `
67+
<ng-container
68+
*ngComponentOutlet="greetingComponent; inputs: greetingInputs()"
69+
/>
70+
`
71+
})
72+
export class ProfileView {
73+
greetingComponent = UserGreeting;
74+
greetingInputs = signal({ username: 'ngAwesome' , role: 'admin' });
75+
}
76+
```
77+
78+
The inputs are updated whenever the `greetingInputs` signal changes, keeping the dynamic component in sync with the parent's state.
79+
80+
### Providing content projection
81+
82+
Use `ngComponentOutletContent` to pass projected content to the dynamically rendered component. This is useful when the dynamic component uses `<ng-content>` to display content.
83+
84+
```angular-ts
85+
@Component({
86+
selector: 'card-wrapper',
87+
template: `
88+
<div class="card">
89+
<ng-content />
90+
</div>
91+
`
92+
})
93+
export class CardWrapper { }
94+
95+
@Component({
96+
imports: [NgComponentOutlet],
97+
template: `
98+
<ng-container
99+
*ngComponentOutlet="cardComponent; content: cardContent()"
100+
/>
101+
102+
<ng-template #contentTemplate>
103+
<h3>Dynamic Content</h3>
104+
<p>This content is projected into the card.</p>
105+
</ng-template>
106+
`
107+
})
108+
export class DynamicCard {
109+
private vcr = inject(ViewContainerRef);
110+
cardComponent = CardWrapper;
111+
112+
private contentTemplate = viewChild<TemplateRef<unknown>>('contentTemplate');
113+
114+
cardContent = computed(() => {
115+
const template = this.contentTemplate();
116+
if (!template) return [];
117+
// Returns an array of projection slots. Each element represents one <ng-content> slot.
118+
// CardWrapper has one <ng-content>, so we return an array with one element.
119+
return [this.vcr.createEmbeddedView(template).rootNodes];
120+
});
121+
}
122+
```
123+
124+
### Providing injectors
125+
126+
You can provide a custom injector to the dynamically created component using `ngComponentOutletInjector`. This is useful for providing component-specific services or configuration.
127+
128+
```angular-ts
129+
export const THEME_DATA = new InjectionToken<string>('THEME_DATA', {
130+
factory: () => 'light',
131+
});
132+
133+
@Component({
134+
selector: 'themed-panel',
135+
template: `<div [class]="theme">...</div>`
136+
})
137+
export class ThemedPanel {
138+
theme = inject(THEME_DATA);
139+
}
140+
141+
@Component({
142+
selector: 'dynamic-panel',
143+
imports: [NgComponentOutlet],
144+
template: `
145+
<ng-container
146+
*ngComponentOutlet="panelComponent; injector: customInjector"
147+
/>
148+
`
149+
})
150+
export class DynamicPanel {
151+
panelComponent = ThemedPanel;
152+
153+
customInjector = Injector.create({
154+
providers: [
155+
{ provide: THEME_DATA, useValue: 'dark' }
156+
],
157+
});
158+
}
159+
```
160+
161+
### Accessing the component instance
162+
163+
You can access the dynamically created component's instance using the directive's `exportAs` feature:
164+
165+
```angular-ts
166+
@Component({
167+
selector: 'counter',
168+
template: `<p>Count: {{count()}}</p>`
169+
})
170+
export class Counter {
171+
count = signal(0);
172+
increment() {
173+
this.count.update(c => c + 1);
174+
}
175+
}
176+
177+
@Component({
178+
imports: [NgComponentOutlet],
179+
template: `
180+
<ng-container
181+
*ngComponentOutlet="counterComponent"
182+
#outlet="ngComponentOutlet"
183+
/>
184+
185+
<button (click)="outlet.componentInstance?.increment()">
186+
Increment
187+
</button>
188+
`
189+
})
190+
export class CounterHost {
191+
counterComponent = Counter;
192+
}
193+
```
194+
195+
NOTE: The `componentInstance` property is `null` before the component is rendered.
196+
44197
See the [NgComponentOutlet API reference](api/common/NgComponentOutlet) for more information on the
45198
directive's capabilities.
46199

0 commit comments

Comments
 (0)