docs: enhance programmatic rendering guide by covering ngComponentOutlet options

(cherry picked from commit f9e9fc4ffe)
This commit is contained in:
SkyZeroZx
2026-01-05 11:49:04 -05:00
committed by kirjs
parent 0b26947802
commit 8eb0cd51de
@@ -41,6 +41,159 @@ export class CustomDialog {
}
```
### Passing inputs to dynamically rendered components
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.
```angular-ts
@Component({
selector: 'user-greeting',
template: `
<div>
<p>User: {{ username() }}</p>
<p>Role: {{ role() }}</p>
</div>
`,
})
export class UserGreeting {
username = input.required<string>();
role = input('guest');
}
@Component({
selector: 'profile-view',
imports: [NgComponentOutlet],
template: `
<ng-container
*ngComponentOutlet="greetingComponent; inputs: greetingInputs()"
/>
`
})
export class ProfileView {
greetingComponent = UserGreeting;
greetingInputs = signal({ username: 'ngAwesome' , role: 'admin' });
}
```
The inputs are updated whenever the `greetingInputs` signal changes, keeping the dynamic component in sync with the parent's state.
### Providing content projection
Use `ngComponentOutletContent` to pass projected content to the dynamically rendered component. This is useful when the dynamic component uses `<ng-content>` to display content.
```angular-ts
@Component({
selector: 'card-wrapper',
template: `
<div class="card">
<ng-content />
</div>
`
})
export class CardWrapper { }
@Component({
imports: [NgComponentOutlet],
template: `
<ng-container
*ngComponentOutlet="cardComponent; content: cardContent()"
/>
<ng-template #contentTemplate>
<h3>Dynamic Content</h3>
<p>This content is projected into the card.</p>
</ng-template>
`
})
export class DynamicCard {
private vcr = inject(ViewContainerRef);
cardComponent = CardWrapper;
private contentTemplate = viewChild<TemplateRef<unknown>>('contentTemplate');
cardContent = computed(() => {
const template = this.contentTemplate();
if (!template) return [];
// Returns an array of projection slots. Each element represents one <ng-content> slot.
// CardWrapper has one <ng-content>, so we return an array with one element.
return [this.vcr.createEmbeddedView(template).rootNodes];
});
}
```
### Providing injectors
You can provide a custom injector to the dynamically created component using `ngComponentOutletInjector`. This is useful for providing component-specific services or configuration.
```angular-ts
export const THEME_DATA = new InjectionToken<string>('THEME_DATA', {
factory: () => 'light',
});
@Component({
selector: 'themed-panel',
template: `<div [class]="theme">...</div>`
})
export class ThemedPanel {
theme = inject(THEME_DATA);
}
@Component({
selector: 'dynamic-panel',
imports: [NgComponentOutlet],
template: `
<ng-container
*ngComponentOutlet="panelComponent; injector: customInjector"
/>
`
})
export class DynamicPanel {
panelComponent = ThemedPanel;
customInjector = Injector.create({
providers: [
{ provide: THEME_DATA, useValue: 'dark' }
],
});
}
```
### Accessing the component instance
You can access the dynamically created component's instance using the directive's `exportAs` feature:
```angular-ts
@Component({
selector: 'counter',
template: `<p>Count: {{count()}}</p>`
})
export class Counter {
count = signal(0);
increment() {
this.count.update(c => c + 1);
}
}
@Component({
imports: [NgComponentOutlet],
template: `
<ng-container
*ngComponentOutlet="counterComponent"
#outlet="ngComponentOutlet"
/>
<button (click)="outlet.componentInstance?.increment()">
Increment
</button>
`
})
export class CounterHost {
counterComponent = Counter;
}
```
NOTE: The `componentInstance` property is `null` before the component is rendered.
See the [NgComponentOutlet API reference](api/common/NgComponentOutlet) for more information on the
directive's capabilities.