0

I'm using angular 2.1 and want to dynamically import a template witch is a string from the backend.

I already use ComponentFactoryResolver to load dynamically my parent container, now I need to create his content witch can look like this:

<my-component>
    <my-nested-component>
    <my-nested-component>
<my-component>

Components are already in my applications, I just need to create them from the template string and load them into the parent.

If create components from string template is not possible, is it possible to do it with lazy loading components ? I see lazy loading with the router but here I under a route and want lazy loading on some composent only

Is it possible ? I know it was possible with angular 2 beta or RC by doing this https://stackoverflow.com/a/39044539/541867

PS: if you want to know why I need to have a template as string coming from the backend it's because the UI of some component is coming from external plugin, they just use a set of component available is the application but can do the layout they want so I can't have it under a @Component template.

EDIT: here is a gist of a first string template I try to load: https://gist.github.com/jaumard/918dfc573b01263467e89adc8ad86f77

Community
  • 1
  • 1
jaumard
  • 8,202
  • 3
  • 40
  • 63
  • I'm not sure if I got it right, but you can store a string in variable and use `*ngIf` when there is no milions of them... what I mean is `` OR if you have a lot of these components you can store them in an array and use `*ngFor`. I know it might not be professional, but it worked when I was working on something similar. – Dawid Zbiński Nov 20 '16 at 10:24
  • I added a gist of what my first template string look like (but there will be much more and much different ones in the future) I don't think it will work the way you said. Am I wrong ? – jaumard Nov 20 '16 at 11:14

2 Answers2

1

If you inject your template in the innerHtml attribute and use the DomSanitizer, it will translate it just like a component, giving you the lazy load effect.

<div [innerHTML]="myComponentsTemplate"></div>

scott
  • 583
  • 6
  • 11
0

Turning strings into components after a component is loaded is blocked for security reasons. [https://angular.io/guide/security]

Constructing a dynamic template service seems to be best practice. Sending in values from the server that would be set into a base class, I think can provide what you are trying to do.

There is an offline template compiler, (https://angular.io/guide/security#offline-template-compiler) An example that shows dynamic component creations is exampled in https://angular.io/guide/dynamic-form#dynamic-template.

I think it this just requires a small bit of refactoring the approach to having a dynamic component, and it is referred to as best practice.

To answer, how to translate a string into a component you need to bypass the security with bypassSecurityTrustHtml(). I prefer using pipes for this. https://angular.io/guide/security#bypass-security-apis

I found this one in a forum https://forum.ionicframework.com/t/inserting-html-via-angular-2-use-of-domsanitizationservice-bypasssecuritytrusthtml/62562/2

import {Pipe, PipeTransform} from '@angular/core';
import {DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';

@Pipe({
    name: 'safe'
})
export class SafePipe implements PipeTransform {

constructor(protected _sanitizer: DomSanitizer) {

}

    public transform(value: string, type: string = 'html'): SafeHtml |  SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
    switch (type) {
        case 'html': return     this._sanitizer.bypassSecurityTrustHtml(value);
        case 'style': return this._sanitizer.bypassSecurityTrustStyle(value);
        case 'script': return this._sanitizer.bypassSecurityTrustScript(value);
        case 'url': return this._sanitizer.bypassSecurityTrustUrl(value);
        case 'resourceUrl': return this._sanitizer.bypassSecurityTrustResourceUrl(value);
        default: throw new Error(`Invalid safe type specified:     ${type}`);
    }
}

}

To implement just use <component-container [innerHtml]='this.safteyPipe.transform(TemplateComponentString)'></component-container>

Rex
  • 376
  • 2
  • 11