Search code examples
javascriptangularcomponentsngforangular-dom-sanitizer

Display <my-component> by [innerHTML]


I'm trying to have my custom component tags in a string array and bind them by ngfor to the innerhtml property after sanitizing them by calling bypassSecurityTrustHtml... unfortunately the output is always empty, but there is also no sanitize error...

What am i doing wrong?

// adminpanel.component.ts
@Component({
    selector: 'admin-panel',
    templateUrl: './adminpanel.component.html'
})
export class AdminPanelComponent {

    static GetRoutes(): Route[] {
        return [
            { path: '', redirectTo: 'news', pathMatch: 'full' },

        // 0
            { path: 'news', component: AdminNewsViewComponent },
        // 1
            { path: 'users', component: AdminUsersViewComponent },
        // 2
            { path: 'roles', component: AdminRolesViewComponent },
        // 3
            {
                path: 'culturesettings',
                redirectTo: 'culturesettings/wordvariables'
            },
            {
                path: 'culturesettings', 
                component: AdminCultureSettingsViewComponent,
                pathMatch: 'prefix',
                children: AdminCultureSettingsViewComponent.GetRoutes()
            },
        // 4
            {
                path: 'account',
                component: AdminAccountViewComponent
            }
        ]
    }

    panels: AdminPanel[] = [];

    routedTabs: RoutedTabs

    constructor(private authService: AuthService, private routerService: RouterService, private sanitizer: DomSanitizer) {
        this.routedTabs = new RoutedTabs("admin/panel", 2, authService, routerService);

        var routes = AdminPanelComponent.GetRoutes().filter(x => x.component != undefined);
        var comps = [
            '<admin-news-view></admin-news-view>',
            '<admin-users-view></admin-users-view>',
            '<admin-roles-view></admin-roles-view>',
            '<admin-culture-settings-view></admin-culture-settings-view>',
            '<admin-account-view></admin-account-view>'
        ];
        for (var i = 0; i < comps.length; i++) this.panels.push(new AdminPanel(i, routes[i], this.sanitizer.bypassSecurityTrustHtml(comps[i])  , this.sanitizer));

    }

    ngOnInit() {

        this.routedTabs.MakeTabs(AdminPanelComponent.GetRoutes());
        this.routedTabs.Subscribe();
        this.routedTabs.Emit();
    }
    ngOnDestroy() {
        this.routedTabs.Unsubscribe()
    }
}
class AdminPanel {
    index: number;
    route: Route;
    innerHtml: any = '';
    constructor(index: number, route: Route, innerHtml: any, private sanitizer: DomSanitizer) {
        this.index = index;
        this.route = route;
        this.innerHtml = innerHtml;

    }
}

And in my adminpanel.component.html:

<mat-tab-group (selectedTabChange)="routedTabs.onTabChange($event)" [(selectedIndex)]="routedTabs.selectedTab">
    <mat-tab *ngFor="let panel of panels" label="{{ routedTabs.tabs[panel.index].label }}">
        <div [innerHTML]="panel.innerHtml">

        </div>
    </mat-tab>
</mat-tab-group>

Solution

  • Just using the tag as a string won't work, as angular doesn't just create component instances if an element with matching selector pops up in the dom.

    You either

    1. use the ComponentFactoryResolver
    2. just have a type property on panel so you use ngSwitch based on type and render the corresponding in an ngSwitchCase. In that case you would have the tags in your template though