2

I am attempting to load a template dynamically at runtime, render it and bind to dynamic data from within the template.

Following the stackoverflow question How to render a dynamic template with components in Angular2 and @Linksonder's answer I have the loading and rendering part up and running.

Now I am stuck at adding an @Input data to the dynamic component and to provide data so that I can bind to it from the template such as {{ data }}.

I extended the ngOnChanges() in this way so that it adds an injector with a test inputProvider:

createComponentFactory(this.compiler, compMetadata)
  .then(factory => {
    let inputProviders = [{provide: 'data', useValue: '1234'}];  
    let resolvedInputs = ReflectiveInjector.resolve(inputProviders);

    const injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.vcRef.parentInjector);

    this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
  });

However, trying to access the injector in DynamicComponent this way throws an error (I assume the Injector can not be resolved):

...
import { Injector} from '@angular/core';

export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {

  const cmpClass = class DynamicComponent {
    data: any;

    constructor(private injector: Injector) {
      this.data = this.injector.get('data');
    }
  };

  const decoratedCmp = Component(metadata)(cmpClass);

  @NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
  class DynamicHtmlModule { }

  return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
   .then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
    return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
  });
}

Any help is appreciated. Also if you have other approaches that solve the problem please let me know.

3
  • I don't know for sure, but you can try: @Component(metadata) class DynamicComponent {...} instead of trying to save the classes in consts? Same way you'd normally define a component basically Commented Apr 14, 2017 at 21:18
  • Did it help anyhow? Commented Apr 14, 2017 at 21:49
  • You can directly set property of component Commented Apr 14, 2017 at 23:15

1 Answer 1

0

I suspect this should work for you:

@Injectable()
class DynamicComponent {
  data: any;

  constructor(private injector: Injector) {
    this.data = this.injector.get('data');
  }
}

export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
    const decoratedCmp = Component(metadata)(DynamicComponent);

    @NgModule({ imports: [CommonModule, RouterModule, SharedModule], declarations: [decoratedCmp] })
    class DynamicHtmlModule { }

    compiler.clearCacheFor(decoratedCmp);
    return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
       .then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
        return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
      });
}

Plunker Example

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

1 Comment

As suggested, the @Injectable decorator was missing. Works nicely now!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.