Konrad Viltersten
Konrad Viltersten

Reputation: 39318

Dynamically added Angular2 component doesn't get rendered but the statically added does

I'm executing the following method when the user clicks a button.

@ViewChild("privs") privs: ElementRef;
addPrivs() {
  this.privs.nativeElement
    .insertAdjacentHTML('beforeend', '<generic1>yey!</generic1>');
}

My markup looks like this.

<generic1>woosh</generic1>
<div #privs></div>

The subcomponent named generic1 is declared like this and, of course, present in imports of the module.

import { Component } from "@angular/core";
@Component({
  selector: "generic1",
  template: "<div>mamba...</div>"
})
export class Generic1 { }

The behavior I'm getting is that the statistically created one in the markup shows as supposed to. The dynamically appended don't. According to the DOM as I investigate, a tag generic1 is added but it's not rendered by Angular (I see the text yey! and the tag but not the rendition of the component).

What am I missing?

I've googled for examples but didn't see anything specifically wrong with my set up. Must be something outside of my scope...

Upvotes: 2

Views: 1366

Answers (1)

Tyler Jennings
Tyler Jennings

Reputation: 8921

You are not actually creating a dynamic component. You are inserting additional HTML that is not rendered by Angular. Html and text are sanitized when inserting them into a template like that and thus you won't get a rendered component.

This answer has a very detailed explanation of setting up dynamic components. However, it is not a copy and paste solution for what you need. The documentation on Angular.io has a good example of a dynamic component loader. Essentially, you will need a ComponentFactoryResolver to resolve and build an Angular component. In the example from the Angular.io docs, the real magic happens in this function:

loadComponent() {
    this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
    let adItem = this.ads[this.currentAddIndex];
    let componentFactory = this._componentFactoryResolver.resolveComponentFactory(adItem.component);
    let viewContainerRef = this.adHost.viewContainerRef;
    viewContainerRef.clear();
    let componentRef = viewContainerRef.createComponent(componentFactory);
    (<AdComponent>componentRef.instance).data = adItem.data;
  }

It retrieves a component from a list of stored components in this.ads, uses a componentFactoryResolver to resolve and build the component. It retrieves the viewContainerRef and creates the component on it.

Hope that helps point you in the right direction.

Upvotes: 2

Related Questions