Dynamic template "transclusion" in Angular2
Asked Answered
A

1

5

I am trying to achieve something like this: I have a model class called ObjectTypeA, ObjectTypeB and ObjectTypeC. There is also a factory ComponentFactory, which based on the type of object passed in will create different components:

ComponentFactory.ts

export interface ComponentFactoryInterface {

    static CreateComponent(obj: CommonSuperObject)

}

@Injectable()
export class ComponentFactory {

    public static CreateComponent(obj: CommonSuperObject){

        if (obj instanceof ObjectTypeA){
            return ObjectComponentA()
        }else if (obj instanceof ObjectTypeB){
            return ObjectComponentB()
        }

    }
}

In the template I would like to do something like this:

main_template.html

<components>
  <component *ngFor="#obj in objects">
     <!-- insert custom component template here -->
  </component>
</components>

How do I insert the associated components dynamically ?

I could do something like this (not my preferred way of doing it):

<components>
  <!-- loop over component models -->
  <custom-component-a *ngIf="models[i] instanceof ObjectTypeA">
  </custom-component-a>
  <custom-component-b *ngIf="models[i] instanceof ObjectTypeB">
  </custom-component-b>
</components>

But this is seems really wrong to me on many levels (I would have to modify this code and the factory code if I add another component type).

Edit - Working Example

constructor(private _contentService: ContentService, private _dcl: DynamicComponentLoader, componentFactory: ComponentFactory, elementRef: ElementRef){

    this.someArray = _contentService.someArrayData;
    this.someArray.forEach(compData => {
    let component = componentFactory.createComponent(compData);
        _dcl.loadIntoLocation(component, elementRef, 'componentContainer').then(function(el){
            el.instance.compData = compData;
        });
    });

}
Auroreaurous answered 24/12, 2015 at 20:38 Comment(0)
C
2

update

DCL is deprecated since a while. Use ViewContainerRef.createComponent instead. For an example (with Plunker) see Angular 2 dynamic tabs with user-click chosen components

original

You can use ngSwitch (similar to your own workaround but more concise) or DynamicComponentLoader

See also

Casandracasanova answered 24/12, 2015 at 20:54 Comment(6)
ngSwitch is not an option, DynamicComponentLoader sounds more like what I am looking for. I'll take a look at that and get back to you.Auroreaurous
Phew! Almost there, I only need to set a property on the newly created component. I get the promise with the ComponentRef back but I'm not really sure how to access properties of the newly loaded component... Any idea ? (Updated my question for you to see what I am working with)Auroreaurous
Okay, I think the component instance would be el.instance. Trying that out and getting back to you shortly.Auroreaurous
Okay got it! Your tip was immensely helpful! Vielen Dank und frohe Weihnachten!Auroreaurous
Since rc1 DynamicComponentLoader has become deprecated.Apotropaic
@AlexandreJunges thanks for the hint :) I updated my answer.Rienzi

© 2022 - 2024 — McMap. All rights reserved.