angularangular-ivy

renderComponent in Angular ivy with extra component/directive declarations


Here is an example of render dynamic lazy component in ivy:

import { ɵrenderComponent as renderComponent, Injector } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-lazy></app-lazy>
  `
})
export class AppComponent {
  constructor(injector: Injector) {
    import('./lazy.component').then(({ LazyComponent }) => {
      renderComponent(LazyComponent, {
        injector,
        host: 'app-lazy'
      });
    });
  }
}

What should I do if we need use extra component/directive in lazy.component?


Solution

  • you need a custom decorator

    import {
      Component,
      Type,
      ɵComponentDef as ComponentDef,
      ɵDirectiveDef as DirectiveDef,
      ɵPipeDef as PipeDef
    } from '@angular/core';
    
    @Component(...)
    @ComponentDeps({
       directives: [...], //***extra component/directive you want***
       pipes: [...] //***extra pipe, like: JsonPipe...***
    })
    export class LazyComponent{
     ...
    }
    
    
    
    export interface ComponentDepsConfig {
      directives?: Type<any>[];
      pipes?: Type<any>[];
    }
    function getDirectiveDef<T>(t: Type<T>): DirectiveDef<T> {
      if (t['ɵdir']) {
        return t['ɵdir'] as DirectiveDef<T>;
      }
      if (t['ɵcmp']) {
        return t['ɵcmp'] as ComponentDef<T>;
      }
      throw new Error('No Angular definition found for ' + t.name);
    }
    function getDirectiveDefs(types: Type<any>[]): DirectiveDef<any>[] {
      return types.map(t => getDirectiveDef(t));
    }
    
    function getPipeDef<T>(t: Type<T>): PipeDef<T> {
      if (t['ɵpipe']) {
        return t['ɵpipe'] as PipeDef<T>;
      }
      throw new Error('No Angular definition found for ' + t.name);
    }
    
    export function getPipeDefs(types: Type<any>[]): PipeDef<any>[] {
      return types.map(t => getPipeDef(t));
    }
    export function ComponentDeps(config: ComponentDepsConfig) {
      return (componentType: Type<any>) => {
        const def = componentType['ɵcmp'] || componentType['ngComponentDef'];
        // directives or components
        def.directiveDefs = [
          ...getDirectiveDefs(config.directives || [])
        ];
        // pipes
        def.pipeDefs = [
          ...getPipeDefs(config.pipes || [])
        ];
      };
    }