2

When trying to use a service in dynamically created component We got this error at run time

ERROR Error: Can't resolve all parameters for class_1: (?). at syntaxError (compiler.js:485) at CompileMetadataResolver._getDependenciesMetadata (compiler.js:15664) at CompileMetadataResolver._getTypeMetadata (compiler.js:15499) at CompileMetadataResolver.getNonNormalizedDirectiveMetadata (compiler.js:15007) at CompileMetadataResolver.loadDirectiveMetadata (compiler.js:14862) at eval (compiler.js:34233) at Array.forEach () at eval (compiler.js:34232) at Array.forEach () at JitCompiler._loadModules (compiler.js:34229)

here is a sample code

  import { Compiler, Component, Injector, VERSION, ViewChild, NgModule, NgModuleRef, OnInit, ViewContainerRef } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { RouterModule } from '@angular/router';
    import { CmsService } from "../../services/cms.service";

    @Component({
      selector: 'home-page',
      template: `
          <ng-container #vc></ng-container>
      `
    })

    export class HomePageComponent implements OnInit {
      constructor(private _compiler: Compiler, private _injector: Injector, private _m: NgModuleRef<any>) { }
      ngOnInit() {

      }
      @ViewChild('vc', { read: ViewContainerRef }) vc;
      ngAfterViewInit() {
        const tmpCmp = Component({ moduleId: module.id, templateUrl: '../../../assets/HomePage/home-page-rbu.component.html' })(
          class {
            constructor(public cms: CmsService) { }
            welcomeTXT: string;
            advertismentTXT: string;
            ngOnInit() {
              this.cms.getCMSItemValue('welcomeTXT').subscribe(res => {
                this.welcomeTXT = res;
              });
              this.cms.getCMSItemValue('advertismentTXT').subscribe(res => {
                this.advertismentTXT = res;
              });

            }
          });

        @NgModule({
          imports: [BrowserModule, RouterModule],
          declarations: [tmpCmp],
          providers: [CmsService]
        })
        class DynamicModule { }

        this._compiler.compileModuleAndAllComponentsAsync(DynamicModule)
          .then((factories) => {
            const f = factories.componentFactories[0];

            const cmpRef = f.create(this._injector, [], null, this._m);
            cmpRef.instance.name = 'dynamic';
            this.vc.insert(cmpRef.hostView);
          })
      }
    }

this sample code was working fine before adding CmsService or any angular service we are using angular 5.1 and angular-cli 1.5

1 Answer 1

2

Workaround for the issue is to access the public properties of the dynamic created componenet using the componentFactories

welcomeTXT: string;
advertismentTXT: string;

as:

this._compiler.compileModuleAndAllComponentsAsync(DynamicModule)
  .then((factories) => {
    const f = factories.componentFactories[0];

    const cmpRef = f.create(this._injector, [], null, this._m);
    cmpRef.instance.welcomeTXT = _welcomeTXT;
    cmpRef.instance.advertismentTXT = _advertismentTXT;
    cmpRef.instance.visitorsCount = _visitorsCount;
    cmpRef.instance.name = 'dynamic';
    this.vc.insert(cmpRef.hostView);
  })

And here is the full code for the component:

import {  Compiler, Component, Injector, VERSION, ViewChild, NgModule, NgModuleRef, OnInit,  ViewContainerRef} from '@angular/core';
import { BrowserModule, DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { CmsService } from "../../services/cms.service";

@Component({
  selector: 'my-app',
  template: `
      <ng-container #vc></ng-container>
  `
})
export class HomePageComponent implements OnInit {
  @ViewChild('vc', { read: ViewContainerRef }) vc;

  constructor(private _compiler: Compiler, private _cms: CmsService, private _injector: Injector, private _m: NgModuleRef<any>, private sanitizer: DomSanitizer) { }
  ngOnInit() {

  }

  ngAfterViewInit() {
    let welcomeTXT: any = "";
    let advertismentTXT: any = "";
    let visitorsCount: number = 0;
    this._cms.getVisitorsCount().subscribe(res => {
      visitorsCount = res;
    });
    this._cms.getCMSItemValue('welcomeTXT').subscribe(res => {
      advertismentTXT = this.sanitizer.bypassSecurityTrustHtml(res);
      this._cms.getCMSItemValue('advertismentTEXT').subscribe(res => {
        welcomeTXT = this.sanitizer.bypassSecurityTrustHtml(res);
        this.CreateHomePageComponent(welcomeTXT, advertismentTXT, visitorsCount);
      });
    });
  }

  CreateHomePageComponent(_welcomeTXT: any, _advertismentTXT: any, _visitorsCount: number) {

    const tmpCmp = Component({ moduleId: module.id, templateUrl: '../../../assets/HomePage/home-page-rbu.component.html' })(
      class {
        welcomeTXT: string;
        advertismentTXT: string;
        visitorsCount: number = 0;
      });

    @NgModule({
      imports: [BrowserModule, RouterModule],
      declarations: [tmpCmp],
      providers: [CmsService]
    })
    class DynamicModule { }

    this._compiler.compileModuleAndAllComponentsAsync(DynamicModule)
      .then((factories) => {
        const f = factories.componentFactories[0];

        const cmpRef = f.create(this._injector, [], null, this._m);
        cmpRef.instance.welcomeTXT = _welcomeTXT;
        cmpRef.instance.advertismentTXT = _advertismentTXT;
        cmpRef.instance.visitorsCount = _visitorsCount;
        cmpRef.instance.name = 'dynamic';
        this.vc.insert(cmpRef.hostView);
      })
  }
}

I wish this help someone

We can also pass the service as variable like visitorsCount

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.