question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Removal of compileComponentAsync in RC6

See original GitHub issue

I’m submitting a … (check one with “x”)

[ ] bug report => search github for a similar issue or PR before submitting
[x] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior With RC6 the method compiler.compileComponentAsync(…) has been replaced with compiler.compileModuleAsync(…). That allows me to render Modules dynamically.

Problem is that if I want to render a single component, I would have to create a module class for each component that should be available dynamically.

Im not saying that rendering modules isn’t a good thing. I would just prefer if it would also be possible to render components directly without the additional overhead.

Expected/desired behavior Would it be possible to bring the old behaviour back?

Reproduction of the problem what I am currently doing:

import {
  Component, Input, ViewChild, ViewContainerRef, Compiler, OnDestroy, OnChanges,
  SimpleChange
} from '@angular/core';

@Component({
  selector: 'dynamic',
  template: `<span #dynComp></span>`
})
export class DynamicComponent implements OnDestroy, OnChanges {
  @Input() dynamicComponent: any;
  @Input() inputs: JSON;
  @Input() outputs: JSON;
  @ViewChild('dynComp', {read: ViewContainerRef}) dynComp;

  public component;

  constructor(
    public view: ViewContainerRef,
    public compiler: Compiler
  ) {}

  public ngAfterViewInit() {
    this.compiler.compileComponentAsync(this.dynamicComponent).then(
      factory => {
        this.component = this.dynComp.createComponent(factory);
        this.bindVariables();
      }
    );
  }

  public ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
    if (this.component) {
      this.bindVariables();
    }
  }

  public ngOnDestroy() {
    this.component.destroy();
  }

  public bindVariables() {
    if (this.inputs !== undefined) {
      let bindingKeys = Object.keys(this.inputs);
      for (let bindingName of bindingKeys) {
        this.component.instance[bindingName] = this.inputs[bindingName];
      }
    }

    if (this.outputs !== undefined) {
      let eventKeys = Object.keys(this.outputs);
      for (let eventName of eventKeys) {
        this.component.instance[eventName] = this.outputs[eventName];
      }
    }
  }
}

What is the expected behavior? Make the rendering of components possible again without the overhead of writing a module for each component.

What is the motivation / use case for changing the behavior? Im not saying that rendering modules isn’t a good thing. I would just prefer if it would also be possible to render components directly without the additional overhead.

Please tell us about your environment:

  • Angular version: 2.0.0-rc.6
  • Browser: [all]
  • Language: [all]

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
simon-sharpcommented, Sep 13, 2016

Hi Igor

Sorry for the late answer. I was on holiday. I have played around with the new Settings you have proposed and could not get it to work:

about 1/: if I run this.componentFactoryResolver.resolveComponentFactory(MyDynamicComponent);

it tells me that there is no componentFactory associated with MyDynamicComponent. I couldn’t find a way to write or generate such a factory.

about 2/: where does generateModule come from? I also found no reference to anything like that.

about my original way that I wanted to avoid: When I am trying to write a module for every Component I get it to work.

This time I have to hand over the Module and the Component. Which is too much overhead. Is there a possibility to get the currently used Module from the context and just use this one? That would also avoid that I have to write a new Module for each dynamically used Component. Plus if I have to generate a component anyway and can not use the bootstrap one, all the Information is already available anyway in the one that already exists.

@Component({
  moduleId: module.id,
  selector: 'dynamic',
  template: `<span #dynComp></span>`,
})
export class DynamicComponent implements OnDestroy, OnChanges {
  @Input() dynamicModule: any;
  @Input() dynamicComponent: any;
  @Input() inputs: JSON;
  @Input() outputs: JSON;
  @ViewChild('dynComp', {read: ViewContainerRef}) dynComp;

  public component: any = new EmptyComponent();

  constructor(
    public view: ViewContainerRef,
    public compiler: Compiler,
    public componentFactoryResolver: ComponentFactoryResolver,
    public injector: Injector
  ) {}

  public ngAfterViewInit() {
    this.compiler.compileModuleAsync(this.dynamicModule).then(
      factory => {
        let moduleInjector: any = factory.create(this.injector);
        this.component = this.dynComp.createComponent(moduleInjector.componentFactoryResolver.resolveComponentFactory(this.dynamicComponent));
        this.bindVariables();
      }
    );
  }

  public ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
    // if (this.component) {
     //  this.bindVariables();
    // }
  }

  public ngOnDestroy() {
    if (typeof this.component.destroy === 'function') {
      this.component.destroy();
    } else {
      this.component = null;
    }
  }

  public bindVariables() {
    if (this.inputs !== undefined) {
      let bindingKeys = Object.keys(this.inputs);
      for (let bindingName of bindingKeys) {
        this.component.instance[bindingName] = this.inputs[bindingName];
      }
    }

    if (this.outputs !== undefined) {
      let eventKeys = Object.keys(this.outputs);
      for (let eventName of eventKeys) {
        this.component.instance[eventName] = this.outputs[eventName];
      }
    }
  }
}
1reaction
zoechicommented, Sep 6, 2016

I assume it’s something like a component can be created dynamically as shown in https://github.com/angular/angular/issues/7596#issuecomment-196881527

Read more comments on GitHub >

github_iconTop Results From Across the Web

Removal of compileComponentsAsync in angular2
With the release of Angular2 RC6 they remove the compileComponentsAsync. and replaced it with compileModuleSync(basically only referencing ...
Read more >
Not reset the template parser's error when using JIT compiler
I'm creating a dynamic component using ngComponentOutlet and whenever I pass some strings like text having only {{}} or a property chain that ......
Read more >
@vue/compiler-sfc | Yarn - Package Manager
@vue/compiler-sfc. Lower level utilities for compiling Vue Single File Components. Note: as of 3.2.13+, this package is included as a dependency of the...
Read more >
Component testing scenarios - Angular
The ComponentFixtureAutoDetect service responds to asynchronous activities such as promise resolution, timers, and DOM events. But a direct, synchronous update ...
Read more >
48 answers on StackOverflow to the most popular Angular ...
A Promise handles a single event when an async operation completes or ... The router will remove this component from the DOM and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found