ng-dynamic-component
Dynamic components with full life-cycle support for inputs and outputs
Version 3.x.x supports Angular 6 (ng-dynamic-component@^3.0.0
)
Version 2.x.x supports Angular 5 (ng-dynamic-component@^2.0.0
)
Version 1.x.x supports Angular 4 (ng-dynamic-component@^1.0.0
)
Version 0.x.x supports Angular 2 (ng-dynamic-component@^0.0.0
)
Installation
$ npm install ng-dynamic-component --save
Usage
Import DynamicModule
with dynamic components you want to insert later:
import { DynamicModule } from 'ng-dynamic-component';
import { MyDynamicComponent1, MyDynamicComponent2 } from './my-components';
@NgModule({
imports: [
DynamicModule.withComponents([MyDynamicComponent1, MyDynamicComponent2])
]
})
DynamicComponent
Then in your component's template include <ndc-dynamic>
where you want to render component
and bind from your component class type of component to render:
@Component({
selector: 'my-component',
template: `<ndc-dynamic [ndcDynamicComponent]="component"></ndc-dynamic>`
})
class MyComponent {
component = Math.random() > 0.5 ? MyDynamicComponent1 : MyDynamicComponent2;
}
Inputs and Outputs
You can also pass inputs
and outputs
to your dynamic components:
@Component({
selector: 'my-component',
template: `<ndc-dynamic [ndcDynamicComponent]="component"
[ndcDynamicInputs]="inputs"
[ndcDynamicOutputs]="outputs"
></ndc-dynamic>`
})
class MyComponent {
component = MyDynamicComponent1;
inputs = {
hello: 'world',
something: () => 'can be really complex'
};
outputs = {
onSomething: (type) => alert(type)
}
}
@Component({selector: 'my-dynamic-component1', template: 'Dynamic Component 1'})
class MyDynamicComponent1 {
@Input() hello: string;
@Input() something: Function;
@Output() onSomething = new EventEmitter<string>();
}
Here you can update your inputs (ex. inputs.hello = 'WORLD'
) and they will trigger standard Angular's life-cycle hooks
(of course you should consider which change detection strategy you are using).
Component Creation Events
You can subscribe to component creation events, being passed a reference to the ComponentRef
:
@Component({
selector: 'my-component',
template: `<ndc-dynamic [ndcDynamicComponent]="component"
(ndcDynamicCreated)="componentCreated($event)"
></ndc-dynamic>`
})
class MyComponent {
component = MyDynamicComponent1;
componentCreated(compRef: ComponentRef<any>) {
// utilize compRef in some way ...
}
}
Attributes
Since v2.2.0 you can now declaratively set attributes, as you would inputs, via ndcDynamicAttributes
:
import { AttributesMap } from 'ng-dynamic-component';
@Component({
selector: 'my-component',
template: `<ndc-dynamic [ndcDynamicComponent]="component"
[ndcDynamicAttributes]="attrs"
></ndc-dynamic>`
})
class MyComponent {
component = MyDynamicComponent1;
attrs: AttributesMap = {
'my-attribute': 'attribute-value',
'class': 'some classes'
};
}
Remember that attributes values are always strings (while inputs can be any value).
So to have better type safety you can use AttributesMap
interface for your attributes maps.
Also you can use ngComponentOutlet
and ndcDynamicAttributes
with *
syntax:
import { AttributesMap } from 'ng-dynamic-component';
@Component({
selector: 'my-component',
template: `<ng-container *ngComponentOutlet="component;
ndcDynamicAttributes: attrs"
></ng-container>`
})
class MyComponent {
component = MyDynamicComponent1;
attrs: AttributesMap = {
'my-attribute': 'attribute-value',
'class': 'some classes'
};
}
NgComponentOutlet support
You can also use NgComponentOutlet
directive from @angular/common
instead of <ndc-dynamic>
and apply inputs
and outputs
to your dynamic components:
@Component({
selector: 'my-component',
template: `<ng-container [ngComponentOutlet]="component"
[ndcDynamicInputs]="inputs"
[ndcDynamicOutputs]="outputs"
></ng-container>`
})
class MyComponent {
component = MyDynamicComponent1;
inputs = {...};
outputs = {...};
}
Also you can use ngComponentOutlet
with *
syntax:
@Component({
selector: 'my-component',
template: `<ng-container *ngComponentOutlet="component;
ndcDynamicInputs: inputs;
ndcDynamicOutputs: outputs"
></ng-container>`
})
class MyComponent {
component = MyDynamicComponent1;
inputs = {...};
outputs = {...};
}
Extra
You can have more advanced stuff over your dynamically rendered components like setting custom injector ([ndcDynamicInjector]
)
or providing additional/overriding providers ([ndcDynamicProviders]
) or both simultaneously
or projecting nodes ([ndcDynamicContent]
).
NOTE: In practice funtionality of this library is splitted in two pieces:
- one - component (
ndc-dynamic
) that is responsible for instantianting and rendering of dynamic components; - two - directive (
ndcDynamic
also bound tondc-dynamic
) that is responsible for carrying inputs/outputs to/from dynamic component by the help of so calledComponentInjector
(it isndc-dynamic
by default).
Thanks to this separation you are able to connect inputs/outputs and life-cycle hooks to different mechanisms of injecting
dynamic components by implementing ComponentInjector
and providing it via DynamicModule.withComponents(null, [here])
in second argument.
It was done to be able to reuse NgComponentOutlet
added in Angular 4-beta.3.
License
MIT © Alex Malkevich