Loading components dynamically
@flyze/lib-core-angular 1.0.0-alpha.34· latestHow to render a component that is chosen at runtime and hand it a configuration.
Prerequisite: DynamicComponentModule imported — see getting-started.
Mechanics: features/dynamic-component-loader.
1. Make a component loadable
Section titled “1. Make a component loadable”Implement DynamicComponent<T> and declare a config property:
export interface TileConfig { title: string; value: number;}
@Component({ selector: 'app-tile', templateUrl: './tile.component.html'})export class TileComponent implements DynamicComponent<TileConfig> { public config: TileConfig;}Do not make config an @Input() — the directive assigns it on the instance, there is no
template binding involved.
config is set before the component’s first change detection, so it is already populated in
ngOnInit. It is not populated in the constructor.
To react to later config changes, declare setConfig instead of a plain property — the directive
prefers it when it exists:
export class TileComponent implements DynamicComponent<TileConfig> { public config: TileConfig;
setConfig(config: TileConfig) { this.config = config; this.recalculate(); }}ngOnChanges never fires for a dynamically loaded component. setConfig is the replacement.
2. Render it
Section titled “2. Render it”<ng-container loadComponent [config]="tile"></ng-container>public tile: DynamicComponentLoaderConfig = { component: TileComponent, config: { title: 'Orders', value: 42 }};The component is inserted after the <ng-container>, as a sibling — the container is an anchor,
not a wrapper.
3. Swap or update it
Section titled “3. Swap or update it”Assign a new config object:
// same component, new data — the instance is kept, setConfig()/config is updatedthis.tile = { component: TileComponent, config: { title: 'Orders', value: 43 } };
// different component — the old instance is destroyed and a new one createdthis.tile = { component: ChartComponent, config: { series: [] } };The directive compares the component reference to decide which of the two happens, so component
state survives a data-only change.
Omitting config entirely leaves the component’s own default in place — it does not reset it to
undefined.
4. Pass an environment
Section titled “4. Pass an environment”For a shared object that every loaded component may need (a gateway, a host API):
<ng-container loadComponent [config]="tile" [environment]="gateway"></ng-container>Only components that already declare the property receive it:
export class TileComponent implements DynamicComponent<TileConfig> { public environment: Gateway; // declared -> assigned // or environment(gateway: Gateway) { … } // a method -> called}A component that declares neither is skipped silently. Rename the target property with
[environmentKey]="'host'".
5. Reference the component by name
Section titled “5. Reference the component by name”When the component name comes out of stored data, register the class and pass the string:
@Component({ … })@DynamicComponentDecorator('TileComponent')export class TileComponent implements DynamicComponent<TileConfig> {}public tile = { component: 'TileComponent', config: { … } };Pass the key explicitly, as a literal. It cannot be derived from the class name: minification renames classes, so a production build would register keys nobody can look up.
Two requirements:
- The key must match the string in the config exactly — it is a plain
Maplookup, no normalization. - The class’s module must have been loaded before the config is used. Registration happens when
the file is evaluated, so a component sitting in a lazy chunk is unknown until that chunk loads.
An unknown key logs
[loadComponent] Component not foundand then throws.
Registering in a barrel file that the app imports eagerly is the simplest way to guarantee both.
Reacting to the load
Section titled “Reacting to the load”<ng-container loadComponent [config]="tile" (componentLoaded)="onLoaded($event)"></ng-container>$event is the ComponentRef. It fires on every create — including the re-create after a component
swap — but before config and environment are applied, so do not read ref.instance.config in
the handler. Use it to keep the ref for later imperative access.
Verify
Section titled “Verify”The /load-component route of the test app loads the same component twice by string key with
different configs.