3

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

Community
  • 1
  • 1
user973671
  • 1,620
  • 6
  • 27
  • 39
  • Is this about dynamic components or dynamic directives. The title and the content are not consistent. – Günter Zöchbauer May 30 '16 at 15:45
  • Sorry, I corrected it. Basically I would be happy to use either, if one of them will work. Thanks – user973671 May 30 '16 at 17:09
  • I don't know Angular1 well. I guess the answer I linked to in my answer below might be what you want, otherwise it would be great if you could explain the problem you're trying to solve. – Günter Zöchbauer May 30 '16 at 17:11
  • I don't think that's it. I added more explanation above. Thanks – user973671 May 31 '16 at 19:12
  • Now I'm even more confident that this is quite similar to the tabs solution linked in my answer below. In addition you need a map from component name to component type (class) because that's what `ViewContainerRef.createComponent()` needs. – Günter Zöchbauer May 31 '16 at 19:15
  • ok, Ill take a closer look ate the tab solution. Thanks – user973671 May 31 '16 at 19:29
  • I think im starting to get it. I still don't fully understand whats going on in the DclWrapper component. Sorry to ask but would you be willing to add some comments to the DclWrapper section of your plunker? https://plnkr.co/edit/Vt9WA3bieeaFMn759ZL1?p=preview – user973671 May 31 '16 at 21:24
  • I updated my answer because it become to long for a comment. – Günter Zöchbauer Jun 01 '16 at 04:21

1 Answers1

1

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.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567