Reputation: 45
I'm trying to call components with the string keys in angular 7. Because my service gives me keys which component filters about to show on page per user. Can i make this filter especially in html?
<pg-tab *ngFor="let tab of tabs; let index = index">
<ng-template #TabHeading>
{{tab.headerText}}
<a (click)="removeTab(index)" style="padding: 5px;"><i class="fa fa-times fa-lg" style="color:orangered;"></i></a>
</ng-template>
<div class="row column-seperation" *ngIf="tab.componentName === 'grid-sample'">
<app-grid-sample></app-grid-sample>
</div>
<div class="row column-seperation" *ngIf="tab.componentName === 'pdf-export-sample'">
<app-pdf-export-sample></app-pdf-export-sample>
</div>
<div class="row column-seperation" *ngIf="tab.componentName === 'notify-sample'">
<app-notify-sample></app-notify-sample>
</div>
<div class="row column-seperation" *ngIf="tab.componentName === 'loader-sample'">
<app-loader-sample></app-loader-sample>
</div>
<div class="row column-seperation" *ngIf="tab.componentName === 'tt-form-elements'">
<app-tt-form-elements></app-tt-form-elements>
</div>
<div class="row column-seperation" *ngIf="tab.componentName === 'tt-layouts'">
<app-tt-layouts></app-tt-layouts>
</div>
</pg-tab>
I searched about innerHtml attribute but it's not working for angular components like in that example.
html
<div [innerHTML]="pageDetail"></div>
typescript
private _pageDetail: string = '<app-tab-page1 [tab]="tab" [tabsLength]="tabs.length" [tabs]="tabs"></app-tab-page1><button>Naber</button>';
public get pageDetail(): SafeHtml {
return this._sanitizer.bypassSecurityTrustHtml(this._pageDetail);
}
You can guess it's not looking good right now. If it's possible, I want to turn shorter and clean that "*ngIf" attributes in html.
Do you have any ideas about it?
Something like this
<div class="row column-seperation" tab.componentName>
<app-tab.componentName></app-tab.componentName>
</div>
Note: Sorry for my grammar mistakes.
Upvotes: 2
Views: 2674
Reputation: 334
You can create a dynamic component with name like this:
Tab item is a directive:
@ViewChildren('tabItem', {read: ViewContainerRef} ) tabItem: QueryList<ViewContainerRef>;
Here create dynamic component:
const factories = Array.from(this.componentFactoryResolver['_factories'].keys());
const factoryClass = <Type<any>>factories.find((x: any) => x.name === dynamicComponentName);
if (factoryClass !== undefined) {
const factory = this.componentFactoryResolver.resolveComponentFactory(factoryClass);
const ref = this.tabItem.viewContainerRef;
ref.createComponent(factory);
}
Also you can look the angular docs: dynamic component
Upvotes: 2
Reputation: 1768
There are two ways:
ngSwitch
will not help much to reduce the html code.ngComponentOutlet
the component to display can be provided from parent component code instead of template.Example for #2:
template:
<div>
... some other code
<ng-template matTabContent>
<ng-container *ngComponentOutlet="screen.component; injector: screen.injector">
</ng-container>
</ng-template>
</div>
Parent component code:
export class TabsContainerComponent implements OnInit {
// make sure these component are also added to entryComponents
private components = [
GridSampleComponent,
NotifySampleComponent,
LoaderSampleComponent,
TTLayoutComponent,
...
];
screen: any; // reference to be used by the ngComponentOutlet in the template
constructor(
private injector: Injector,
) {}
async ngOnInit() {
const tabs = await this.someApiService.getComponentFilters().toPromise();
const injector = Injector.create({
providers: [any providers you want to pass to the component],
parent: this.injector
})
switch (tabs.componentName) {
case 'grid-sample':
screen = { component: GridSampleComponent, injector };
break;
case 'notify-sample':
screen = { component: NotifySampleComponent, injector };
break;
case 'loader-sample':
screen = { component: LoaderSampleComponent, injector };
break;
case 'tt-layout':
screen = { component: TTLayoutComponent, injector };
break;
}
}
}
Upvotes: 0
Reputation: 6646
You could simply use ngSwitch which will make it shorter, but dynamic component name is from what i know not possible,
<div class="row column-seperation" *ngSwitch="tab.componentName">
<app-grid-sample *ngSwitchCase="'grid-sample'"></app-grid-sample>
<app-pdf-export-sample *ngSwitchCase="'pdf-export-sample''"></app-pdf-export-sample>
//etc ...
</div>
Upvotes: 0