3

I am looping through a list of metrics and inside each loop there is a button that would be clicked to render a graph at a specific div within the HTML of the loop. The graph is a separate component, however I cannot seem to figure out how to target the correct HTML element to load the graph component into. I started by creating a component rendering function and call it like this:

loadMetricGraph(metric) {
  let selector = "[id=metricGraph-" + metric.id + "]";
  this.renderComponent(LineGraphHorizontalComponent, selector, metric.data);
}    

renderComponent(componentClass, selector, data) {
  return this.compiler
    .compileComponentAsync(componentClass)
    .then((factory:ComponentFactory<any>) => {
      let cmpRef:ComponentRef<any> =
        factory.create(this.injector, null, selector);
      cmpRef.instance.inputData = data;
      (<any>this.appRef)._loadComponent(cmpRef);
      return cmpRef;
    });
}

In the loop I have a div that would be the target for the loaded component, however I am stuck on how to pass the correct selector to the renderComponent() function. I have attempted to use id="graphData-{{ metric.id }}" And then a selector of "[id=graphData-" + metric.id + "]". I know this is not the correct way to do this, but I am not sure how to proceed.

0

1 Answer 1

4

You can't dynamically add HTML and get components or directives created for this HTML. If you want to dynamically add components then you need to use ViewContainerRef.createComonent.

See Angular 2 dynamic tabs with user-click chosen components shows how to do this declaratively using a helper component.

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

7 Comments

I am not attempting to dynamically add HTML, the HTML is added in the *ngFor when the base component is loaded. I am attempting to target the existing HTML elements in the loop by an id or something dynamic to load the graph component. The example you linked shows how to do this when you already know the attribute of the target, in this case #target. I need to do this dynamically for each instance of the loop where the target is unknown until a click occurs.
No, #target is inside the helper component. *ngFor adds the helper component (<dcl-wrapper>) and configures it with the type <dcl-wrapper> should add inside itself. I think it's the only sane way. With your approach you would need to sync the HTML elements created by *ngFor with the dynamically created components. That seems really complicated, while my approach is quite simple.
I guess I am not understanding your approach. I am trying to reuse the LineGraphHorizontalComponent class multiple times and inject an instance of it into a specific element location within the structure of the looped HTML. I do not have a list of pre-defined child components that need to be picked from, rather a reusable graph component that is passed data and renders a graph that should be placed in a specific location.
I guess it would be helpful if you would add the code to your question that demonstrates how you generate the HTML and where you want to add the component. I have no idea what "specific element location within the structure of the looped HTML" means.
I documented it in the question, I have a div element with an id tag like id="metricGraph-{{ metric.id }}", and I simply want to target that div to load the component into. I cannot figure out a better way to give that div element a dynamic target than using and id, or if there is an alternative way to target a div that I am unaware of. factory.create(this.injector, null, selector) requires a valid selector and I am trying to figure out how to pass it a valid selector that I can generate dynamically when the DOM is created.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.