Reputation: 1640
I am converting an angular 1 application to angular 2. I have the dynamic directives working in angular 1 in a ng-repeat. I went off of this plunker http://plnkr.co/edit/ET3LZhXBRjwIsbKVIwxm?p=preview
<tr ng-repeat="p in people">
<td dynamic-directive="p.dir" blah="p"></td>
</tr>
from this question : Angularjs dynamic directive inside ngrepeat
Is it possible to do the basically the same thing with angular 2? My data model will tell me what component to use and what data to pass in to the component.
Edit: So my use case is: My main page on my site can have 10 different widgets and each widget is a different component - currently a directive in angular 1. Each component needs different data. The components can be in any order depending on how the site admin adds them in the database. I get the data from an API. In the data structure, there is a one to many: component > data. I need to loop through the data and add the components dynamically based on the component name from the data set. The data structure looks something like this.
"Topics":[
{
"component":"header",
"Slug":"fake-slug",
"URL":"some-image"
},
{
"component":"standardcontent",
"Slug":"fake-slug",
"URL":"some-image"
},
{
"component":"playlist",
"PlayLists":[
{
"CONPlaylistID":"22",
"description":"fake-description",
"image":"fake-image"
},
{
"CONPlaylistID":"22",
"description":"fake-description",
"image":"fake-image"
}
]
}
]
Thanks in advance
Upvotes: 3
Views: 4805
Reputation: 657058
Directives can only be added by static HTML that matches the directive selector and there is no other mechanism to depend directive instantiation on.
You can use two similar elements where one matches the directive selector and the other doesn't and switch between them:
<tr *ngFor="let p of people">
<td *ngIf="doAddDirective" dynamic-directive="p.dir" blah="p"></td>
<td *ngIf="!doAddDirective" blah="p"></td>
</tr>
If it's about components instead of directives this might be what you want Angular 2 dynamic tabs with user-click chosen components
update
Some explanation what <dcl-wrapper>
does:
There are two main things, the rest is only to wrap it in a component for easier reuse.
The first is the ViewContainerRef
and how to get it. This defines where the dynamically component will be added. You can either inject ViewContainerRef
then the dynamically component will be added below (not inside) the current component
or you can acquire it from an element in the template of the current component using @ViewChild(..., {read: ViewContainerRef})
, then the dynamically added element will be inserted below that element.
The 2nd part is resolveComponent()
with target.createComponent()
that is the code that actually inserts the dynamic component.
The dcl-wrapper
component is to make it easy to declaratively add dynamic components. Just add
<dcl-wrapper [type]="item.type"></dcl-wrapper>
to your template (assuming item
is from *ngFor
referring to an item of your JSON).
This will add a <dcl-wrapper></dcl-wrapper>
component to your component and the <dcl-wrapper>
will then add the dynamic component returned by item.type
inside itself. The other code in <dcl-wrapper>
is for when item.type
changes to remove the previously added dynamic component and add the one item.type
now refers to.
hint
The dynamic component item.type
needs to be a type reference not a string name. Therefore you need a way to get the component type from the name.
You could provide a global service that returns the type from the name. You would need to maintain the mapping manually. There are ways to get the type from a name string imperatively in TypeScript but I haven't found the SO question/answer where this is explained.
Upvotes: 1