0

I would like to create an angle component that consists of several sub-components. Eventually I want to create a large reusable tree component whose nodes have different data types. For each data type, the tree component imports sub-components that specify how the node should be displayed. The user should be able to specify a custom component to override the default component for a particular data type. An import syntax like this would be nice:

<app-tree [customDateComp]="CustomDateComponent"></app-tree>

This could be the simplified tree.component.html:

<ng-container *ngIf="!customDateComp">
 <app-default-date></app-default-date>
</ng-container>
<ng-container *ngIf="customDateComp">
 {{ customDateComp }}
</ng-container>

Of course this does not work yet, because the components are imported with the syntax. The approach below does not work either, because angular escapes it:

<app-tree [customDateComp]="'<app-custom-date></app-custom-date>'"></app-tree>

The sample code can be found here: https://stackblitz.com/edit/angular-ivy-xghj5f?file=src/app/app.component.html

Does anyone have an idea how to import Angular Components into other Components by specifying the component name as an input parameter? Or is there a better way to override default sub-components of a third-party component? Thanks a lot!

Tom
  • 1,358
  • 2
  • 14
  • 36
  • Have a look at `ng-content` think that will do what you need – penleychan Sep 14 '20 at 12:25
  • maybe [dynamic-component-loader](https://angular.io/guide/dynamic-component-loader)? – Asaf Sep 14 '20 at 12:26
  • 1
    Does this answer your question? [How can I use/create dynamic template to compile dynamic Component with Angular 2.0?](https://stackoverflow.com/questions/38888008/how-can-i-use-create-dynamic-template-to-compile-dynamic-component-with-angular) – Asaf Sep 14 '20 at 12:27

2 Answers2

2

Here is your stackblitz demo working.

Among the possible approaches, there is a portal (and the utilities available from @angular/cdk/portal).

Basically, this is what you need:

1 - A placeholder (in this case, cdkPortalOutlet setup) for the received component:

<ng-template [cdkPortalOutlet]="_compPortal"></ng-template>

2 - A portal (_compPortal, above) to plug into your portal outlet:

_compPortal = new ComponentPortal<any>(MyCustomComponent);

That's all.

In your case (the stackblitz you've linked in your question) you can do:

0 - Import @angular/cdk/portal module:

import {PortalModule} from '@angular/cdk/portal';

@NgModule({imports: [ ... PortalModule ] ...}) export class AppModule { }

1 - tree.component.html

<ng-container *ngIf="!_compPortal">
 <app-date></app-date>
</ng-container>
<ng-container *ngIf="_compPortal">
  <ng-template [cdkPortalOutlet]="_compPortal"></ng-template>
</ng-container>

2 - tree.compoenent.ts

@Input() 
set customDateComp(customComp: any){
  this._compPortal = customComp ? new ComponentPortal(customComp) : null;
}
_compPortal: ComponentPortal<any>;

3 - app.component.ts

// Notice this is not `_comp: CustomDateComponent`.
// I'm setting up an attribute that receives the type so I can 
// make it available on the template
_comp = CustomDateComponent;

4 - app.component.html

<app-tree [customDateComp]="_comp"></app-tree>
julianobrasil
  • 8,954
  • 2
  • 33
  • 55
0

You can use Dynamic component loader https://angular.io/guide/dynamic-component-loader

Hai Mai
  • 370
  • 2
  • 6