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.

Cannot insert multiple Dynamic Components in one ViewContainerRef

See original GitHub issue

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

When calling ViewContainerRef.insert(viewRef: ViewRef) multiple times to add multiple dynamic components only the last dynamic component will be attached to the dom.

Expected behavior

Multiple dynamic components are attached to the dom.

Minimal reproduction of the problem with instructions

export class DynamicComponent {
  currentComponent;

  @ViewChild('dynamicComponentContainer', {
    read: ViewContainerRef
  }) dynamicComponentContainer: ViewContainerRef;

  @Input() set componentData(data: {
    component: any,
    inputs: any
  }) {
    if (!data) {
      return;
    }
    let inputProviders = Object.keys(data.inputs).map((inputName) => {
      return {
        provide: inputName,
        useValue: data.inputs[inputName]
      };
    });
    let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
    let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector);
    let factory = this.resolver.resolveComponentFactory(data.component);
    let component = factory.create(injector);

    // Insert the component into the dom container
    this.dynamicComponentContainer.insert(component.hostView);
    this.currentComponent = component;
  }

  constructor(private resolver: ComponentFactoryResolver) { }
}

When called from AppComponent

  createComponent<T>(component: T) {
      this.componentData = {
        component: component,
        inputs: {
          input: 1
        }
      }
  }

  createComponents() {
    this.createComponent(OneComponent);
    this.createComponent(TwoComponent);
    // There are more components to add
  }

  ngAfterViewInit() {
      this.createComponents();
  }

Workaround

Set immediate timeout solves the issue, but it is very dirty

  createComponent<T>(component: T) {
    setTimeout(() => {
      this.componentData = {
        component: component,
        inputs: {
          input: 1
        }
      }
    }, 0);

I didn’t understand yet why the workaround is even working, maybe has something to do with change detection.

Please let me know if this is easily reproducible otherwise I can add a stackblitz.

What is the motivation / use case for changing the behavior?

With the current behavior it is impossible to attach multiple dynamic components to the dom and the workaround is dirty.

Environment


Angular version: 5.0.0, 5.2.0 and 5.2.3


Browser:
- [x] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 
For Tooling issues:
- Node version: 9.4.0 
- Platform:  Windows

Others:

Cheers, Mo

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:12 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
mboughabacommented, Feb 5, 2018

Hi @Yerkon, Indeed this is similar 👍 Thanks. In my case I am using @ViewChildwith my ViewContainerRefto insert all of the dynamic children.

  @ViewChild('dynamicComponentContainer', {
    read: ViewContainerRef
  }) dynamicComponentContainer: ViewContainerRef;
1reaction
mboughabacommented, Mar 26, 2018

@jburtondev glad it helped, Another solution would be to call detectChanges on changeDetectorRef

  public createComponent<T extends LeafComponent, A extends ComponentAttributes>(component: T, attribute: A, payload: A) {
    this.dynamicContent = {
      component,
      attribute,
      payload
    };

    // NOTE: This is required because dynamicContent will be changed after ViewInit of parent.
    this.cdr.detectChanges();
  }

  constructor(protected cdr: ChangeDetectorRef) {
    super();
  }
Read more comments on GitHub >

github_iconTop Results From Across the Web

Create multiple different dynamic components using ngFor ...
I would like to insert a dynamic list of ...
Read more >
Angular dynamic component — mount once, insert on demand
I created a simple demo to test if during navigation between two routes the component would be created only once and properly reused...
Read more >
Here is what you need to know about dynamic components in ...
We start with the comparison of dynamic components functionality in Angular ... a component instance from it and insert into a DOM using...
Read more >
How to use ViewContainerRef with dynamic components from ...
The error happens on the last line, when trying to run the `ViewContainerRef.insert`. Error: ERROR TypeError: Cannot read property '1' of ...
Read more >
Dynamic Components - Angular - w3resource
Dynamic Components in any framework/library makes building large-scale apps way easier. Angular enables dynamic component loading.
Read more >

github_iconTop Related Medium Post

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