ng-dynamic-component
Dynamic components with full life-cycle support for inputs and outputs
Hey! There is a proposal for new API!
So if you are using this library please give your vote/feedback.
Installation
Usage
DynamicComponent
Import DynamicModule
where you need to render dynamic components:
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:
Standalone API
Since v10.7.0
You may use <ndc-dynamic>
as a standalone component:
NOTE: Hovewer you should be aware that this will only import <ndc-dynamic>
into your component and nothing else so things like dynamic inputs/outputs will not work and you will have to import them separately (see their respective sections).
If you still need to use both <ndc-dynamic>
and dynamic inputs/outputs it is recommended to keep using DynamicModule
API.
NgComponentOutlet
You can also use NgComponentOutlet
directive from @angular/common
instead of <ndc-dynamic>
.
Import DynamicIoModule
where you need to render dynamic inputs:
Now apply ndcDynamicInputs
and ndcDynamicOutputs
to ngComponentOutlet
:
Also you can use ngComponentOutlet
with *
syntax:
Standalone API
Since v10.7.0
You may use dynamic inputs/outputs with *ngComponentOutlet
as a standalone API:
If you want to use standard dynamic inputs/outputs with ngComponentOutlet
as a standalone API you need to add the DynamicIoDirective
to your imports:
Inputs and Outputs
You can pass inputs
and outputs
to your dynamic components:
Import module DynamicIoModule
and then in template:
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).
Standalone API
Since v10.7.0
You can use standalone API to pass dynamic inputs/outputs using DynamicIoDirective
with DynamicComponent
or ngComponentOutlet
:
Output template variables
Since v6.1.0
When you want to provide some values to your output handlers from template - you can do so by supplying a special object to your output that has shape {handler: fn, args: []}
:
Here you can specify at which argument event value should arrive via '$event'
literal.
HINT: You can override event literal by providing IoEventArgumentToken
in DI.
Output Handler Context
Since v10.4.0
You can specify the context (this
) that will be used when calling the output handlers by providing either:
IoEventContextToken
- which will be; injected and used directly as a context valueIoEventContextProviderToken
- which will be provided and instantiated within theIoService
and used as a context value. This useful if you have some generic way of retrieving a context for every dynamic component so you may encapsulate it in an Angular DI provider that will be instantiated within every component's injector;
Example using your component as an output context:
Component Creation Events
You can subscribe to component creation events, being passed a reference to the ComponentRef
:
Attributes
Since v2.2.0 you can now declaratively set attributes, as you would inputs, via ndcDynamicAttributes
.
Import module DynamicAttributesModule
and then in template:
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:
Standalone API
Since v10.7.0
You can use standalone API to pass dynamic inputs/outputs using DynamicAttributesDirective
with DynamicComponent
or ngComponentOutlet
:
Directives (experimental)
Since v3.1.0 you can now declaratively set directives, via ndcDynamicDirectives
.
NOTE: There is a known issue with OnChanges hook not beign triggered on dynamic directives since this part of functionality has been removed from the core as Angular now supports this out of the box for dynamic components.
In dynamic directives queries like
@ContentChild
and host decorators like@HostBinding
will not work due to involved complexity required to implement it (but PRs are welcome!).
Import module DynamicDirectivesModule
and then in template:
It's also possible to bind inputs and outputs to every dynamic directive:
To change inputs, just update the object:
You can have multiple directives applied to same dynamic component (only one directive by same type):
Standalone API
Since v10.7.0
You can use standalone API to pass dynamic inputs/outputs using DynamicDirectivesDirective
with DynamicComponent
or ngComponentOutlet
:
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]
).
Since v10.6.0: You can provide custom NgModuleRef ([ndcDynamicNgModuleRef]
) or EnvironmentInjector ([ndcDynamicEnvironmentInjector]
) for your dynamic component.
NOTE: In practice functionality of this library is split in two pieces:
one - component (
ndc-dynamic
) that is responsible for instantiating 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 calledDynamicComponentInjector
.
Thanks to this separation you are able to connect inputs/outputs and life-cycle hooks to different mechanisms of injecting dynamic components by implementing DynamicComponentInjector
and providing it via DynamicComponentInjectorToken
in DI.
It was done to be able to reuse NgComponentOutlet
added in Angular 4-beta.3.
To see example of how to implement custom component injector - see ComponentOutletInjectorDirective
that is used to integrate NgComponentOutlet
directive with inputs/outputs.
Contributing
You are welcome to contribute to this project. Simply follow the contribution guide.
License
MIT © Alex Malkevich
Last updated