0

We have to bind the template from API and then damContentRoot declared as the public variable in component. But it is not getting reflected.

   @Component({
    selector: 'app-plans',
    template: '<div *ngIf="pageTemplate" [innerHTML]="pageTemplate | safeHtml"></div>'
})
export class PlansComponent {
   public pageTemplate: string;
   public damContentRoot: string;
   public ngOnInit(): void {
   this.damContentRoot = "abcde";
   this.pageTemplate = `<div>Goog <span [innerHtml]="damContentRoot"></span>
                <span [innerHtml]="'<p>Yahoo</p>'"></span></div>`;

   }
}

damContentRoot do not get updated. Tried dynamic component but then damContentRoot become out of scope variable for that component.

2 Answers 2

2

You can create your own directive that will do it:

compile.directive.ts

              @Directive({
                selector: '[compile]'
            })
                export class CompileDirective implements OnChanges {
            @Input() compile: string;
              @Input() compileContext: any;

                compRef: ComponentRef<any>;

                constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}

                ngOnChanges() {
                    if(!this.compile) {
                        if(this.compRef) {
                            this.updateProperties();
                            return;
                        }
                        throw Error('You forgot to provide template');
                    }

                    this.vcRef.clear();
                    this.compRef = null;

                    const component = this.createDynamicComponent(this.compile);
                    const module = this.createDynamicModule(component);
                    this.compiler.compileModuleAndAllComponentsAsync(module)
                        .then((moduleWithFactories: ModuleWithComponentFactories<any>) => {
                            let compFactory = moduleWithFactories.componentFactories.find(x => x.componentType === component);

                            this.compRef = this.vcRef.createComponent(compFactory);
                            this.updateProperties();
                        })
                        .catch(error => {
                            console.log(error);
                        });
                }

                updateProperties() {
                    for(var prop in this.compileContext) {
                        this.compRef.instance[prop] = this.compileContext[prop];
                    }
                }

                private createDynamicComponent (template:string) {
                @Component({
                        selector: 'custom-dynamic-component',
                        template: template,
                    })
                    class CustomDynamicComponent {}
                    return CustomDynamicComponent;
                }

                private createDynamicModule (component: Type<any>) {
                @NgModule({
                        // You might need other modules, providers, etc...
                        // Note that whatever components you want to be able
                        // to render dynamically must be known to this module
                        imports: [CommonModule],
                        declarations: [component]
                    })
                    class DynamicModule {}
                    return DynamicModule;
                }
            }

Usage:-

            import { Component, Input, NgModule } from '@angular/core'
            import { BrowserModule } from '@angular/platform-browser'

            import { CompileDirective } from './compile.directive';

            @Component({
                selector: 'my-app',
                template: `
            <div class="product"><ng-container *compile="template1; context: this"></ng-container></div>
            `,
            })
            export class App {
                damContentRoot = "abcde";
              @Input() template1: string = `<div>Goog <span [innerHtml]="damContentRoot"></span><span [innerHtml]="'<p>Yahoo</p>'"></span></div>`;
            }

            @NgModule({
                imports: [ BrowserModule ],
                declarations: [ App, CompileDirective ],
                bootstrap: [ App ]
            })
            export class AppModule {}
            }

Plunker

Sign up to request clarification or add additional context in comments.

3 Comments

This works fine on local but fail with prod build. Says Error: Runtime compiler is not loaded
To use this in angular 6 you need to build without aot and build-optimizer: ng build --prod --aot=false --build-optimizer=false
This makes the main.js file much bigger so it isn't a long term solution. In my case my main.js is 556k with a normal --prod build and 1.2MB with --aot=false --build-optimizer=false.
0

pageTemplate is a string, but you are treating as a Boolean value in template , if you want to use it as above, you shoud convert it to a bollean value.

or check for the appropriate value in ngIf

template: '<div *ngIf="pageTemplate === 'yourStringvalue'" [innerHTML]="pageTemplate | safeHtml"></div>'

1 Comment

damContentRoot is not getting binded in innerHTML. Though it is the component public variable.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.