0

When creating dynamic components on Angular 4, I used ngComponentOutlet. My code works well in development but not in production.

@Component({
  selector: 'dynamic-detail',
  template: `<ng-container *ngComponentOutlet="dynamicComponent; ngModuleFactory: dynamicModule;"></ng-container>`,
})
export class DynamicDetail implements OnInit {
  ...
  public ngOnInit(): void {
    var template = '<a custom-directive> </a>';

    this.dynamicComponent = this.createNewComponent(template);
    this.dynamicModule = this.compiler.compileModuleSync( this.createComponentModule( this.dynamicComponent ) );
  }

  protected createNewComponent(tmpl: string) {
    @Component({ selector: 'dynamic-component', template: tmpl })
    class CustomDynamicComponent{ constructor() {} };
    return CustomDynamicComponent;
  }

  protected createComponentModule(componentType: any) {
    @NgModule({
        imports: [  WidgetsModule ],
        entryComponents: [ componentType ],
        declarations: [ componentType ],
    })
    class RuntimeComponentModule { }
    return RuntimeComponentModule;
  }
} 

The widgets module contains the export and declaration of the customDirective. When I run the code it works. but if I build with production flag it gives the error:

vendor.js:1 ERROR Error: No component factory found for l. Did you add it to @NgModule.entryComponents?

at B (vendor.js:1)
at t.resolveComponentFactory (vendor.js:1)
at t.ngOnChanges (vendor.js:1)
at vendor.js:1
at vendor.js:1
at on (vendor.js:1)
at Sn (vendor.js:1)
at Object.updateDirectives (main.js:1)
at Object.updateDirectives (vendor.js:1)
at rn (vendor.js:1)
(anonymous) @ vendor.js:1
vendor.js:1 ERROR Error: Uncaught (in promise): Error: Unexpected value 'n' 
imported by the module 'l'. Please add a @NgModule annotation.
Error: Unexpected value 'n' imported by the module 'l'. Please add a @NgModule annotation.
at l (vendor.js:1)
at vendor.js:1
at Array.forEach (<anonymous>)
at t.getNgModuleMetadata (vendor.js:1)
at t._loadModules (vendor.js:1)
at t._compileModuleAndComponents (vendor.js:1)
at t.compileModuleSync (vendor.js:1)
at t.compileModuleSync (vendor.js:1)
at n.refreshContent (main.js:1)
at n.ngOnChanges (main.js:1)
at l (vendor.js:1)
at vendor.js:1
at Array.forEach (<anonymous>)
at t.getNgModuleMetadata (vendor.js:1)
at t._loadModules (vendor.js:1)
at t._compileModuleAndComponents (vendor.js:1)
at t.compileModuleSync (vendor.js:1)
at t.compileModuleSync (vendor.js:1)
at n.refreshContent (main.js:1)
at n.ngOnChanges (main.js:1)
at c (polyfills.js:3)
at c (polyfills.js:3)
at polyfills.js:3
at t.invokeTask (polyfills.js:3)
at Object.onInvokeTask (vendor.js:1)
at t.invokeTask (polyfills.js:3)
at r.runTask (polyfills.js:3)
at o (polyfills.js:3)

1 Answers1

0

I think the problem here is that when you build the --prod mode, class names are obfuscated (hence the error 'n' was not found)

your CustomDirective's name is obfuscated to n. The compiler tries to create this type 'n' and cannot find a definition.

I had a similar problem when I tried to create components via the component factory resolver. My solution was to create a static variable in my component that corresponded to the class name.

When I then created the component dynamically, i searched the available factories for this name.

var factories = Array.from(this.componentFactoryResolver['_factories'].keys());
      return <Type<any>>factories.find((x: any) => x.componentName === name);

I'm not sure what your createNewComponent() does, but I guess that should be done in there.

A good answer that elaborates on the solution can be found here: https://stackoverflow.com/a/40662376/4827723

lama
  • 362
  • 1
  • 2
  • 9
  • I have added the createNewComponent() to the code – Medunoye Laxus Gbenga Mar 21 '18 at 19:33
  • So you want to use the JIT compiler with AoT? As far as I know that is not possible, at least it was half a year ago. There is an issue that adresses this, with some possible work-arounds posted. https://github.com/angular/angular/issues/15510 – lama Mar 22 '18 at 10:55