1

I can't figure out how to attach a dinamically created component to a DOM element created by an external JS library.

This is the code inside my root component:

markers.push(
    L.marker(
      [mapEvent.lng, mapEvent.lat],
      {
        icon: L.icon({
          iconUrl: mapEvent.iconURL,
          iconSize: [22, 22],
          iconAnchor: [11, 11] // point of the icon which will correspond to marker's location
        })
      }
    ).bindPopup(
      L.popup(
        {
          closeButton: true
        }
      ).setContent(
        '<template #popupHost></template>'
      )
    )
  );

Essentially, this code is creating some elements inside the DOM that are not handled by me, and I want to use the setContent method to put my own code. What i would like to do is to inject a component inside this dynamically.

How can I solve this?

Thanks

Cordair
  • 63
  • 1
  • 9
  • I've already read those solutions but nothing is working in my case... i'm blocked because when I try to call createComponent(factory) on the ViewContainerRef object (created by @ChildView), i get a 'Cannot read property 'createComponent' of undefined' – Cordair Sep 25 '17 at 14:23
  • Please create plunker with your issue. I will have a look – yurzui Sep 25 '17 at 14:25
  • MapComponent is using Leaflet to create a map and place some markers. Clicking on markers i want to see my own popup box, style and text, and also i want it to interact with the state of the map. This means that i can't use a static way to do this. https://plnkr.co/edit/czNxh4HmRMVp2HvfHrmM?p=catalogue – Cordair Sep 25 '17 at 14:37
  • `I've already read those solutions but nothing is working in my case` i guess you didn't read these answers ) I'm working on your example – yurzui Sep 25 '17 at 14:52
  • How do you build map? Do you use @asymmetrik/angular2-leaflet? – yurzui Sep 25 '17 at 14:54
  • yes. i'm using it – Cordair Sep 25 '17 at 15:18

1 Answers1

1

You can do it without ViewContainerRef but you should have access to DOM element where you want to place your dynamic component.

First of all you need to create instance of your component like:

constructor(
  private resolver: ComponentFactoryResolver, 
  private inj: Injector) {}
...
const factory = this.resolver.resolveComponentFactory(PopupComponent);
this.componentRef = factory.create(this.inj);

then you need to configure your communication with this component:

export class PopupComponent {

  text: String;

  @Output() textChanged = new EventEmitter();  
}

this.componentRef.instance.text = popup.options.data;
this.subscription = this.componentRef.instance.textChanged.subscribe((val) => {
        this.data = val;
     });

after that you need to add component to the DOM

someDOMElement.appendChild((this.componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);

and finally make sure that your component is checked by angular change detection:

host.component.ts

ngDoCheck() {
   if(this.componentRef) {
     this.componentRef.changeDetectorRef.detectChanges();
   }
}

Plunker Example

See also

yurzui
  • 205,937
  • 32
  • 433
  • 399