将动态创建的组件注入动态创建的树形图中

时间:2019-03-26 13:38:44

标签: angular d3.js

我必须动态创建树形图(之所以选择D3.js,是因为它可以进行更多的自定义,原因是该图需要大量自定义,但这不是明确的要求。

该图的创建方式类似于可扩展树图的示例(例如https://observablehq.com/@d3/collapsible-tree),不同之处在于我需要将自定义组件作为节点;该组件都需要显示可能的动态数据(尽管可以通过重绘来显示),但最重要的是我需要它来处理事件(单击组件的不同部分)。 使用我的代码(在下面提供),实际上就创建了该组件,并根据我的输入对它的模板进行了评估,但是此后,我找不到将其实际注入到节点中的方法。 在我的代码中,我能够将HTML注入节点中,并且可以在DOM中正确可视化,但是事件处理显然以这种方式丢失(我猜这些操作会丢失Angular位)。 有没有办法实现我的目标?我不知道的API(我尝试过渲染器appendChild,但似乎找不到找到实际父节点的方法),或者用另一种方法将其写出

这是从示例中获得的唯一变化

nodeEnter.append("foreignObject").attr("width", "100").attr("height", "100")
          .attr("dy", "0.31em")
          .attr("y", d => d._children ? -6 : 6)
          .attr("text-anchor", d => d._children ? "end" : "start")
          .html((d: d3.HierarchyNode<Graph>) => this.buildComponent(d.data))
        .clone(true).lower()
          .attr("stroke-linejoin", "round")
          .attr("stroke-width", 3)
          .attr("stroke", "white");

这是buildComponent方法:

buildComponent(graph: Graph) {
    const factory = this.componentFactoryResolver.resolveComponentFactory(PocDataComponent);
    const inputs = [
      {
      'provide': 'entity',
      'useValue': graph
      }
    ];
    const injector = ReflectiveInjector.fromResolvedProviders(ReflectiveInjector.resolve(inputs), this.injector);
    const newLocal = factory.create(injector);
    newLocal.instance.entity = graph;
    newLocal.changeDetectorRef.detectChanges();
    // tslint:disable-next-line: no-string-literal
    return newLocal.hostView['rootNodes'][0].innerHTML;

  }

图形是一个包含业务信息的简单对象对象

1 个答案:

答案 0 :(得分:0)

在这篇文章(https://malcoded.com/posts/angular-dynamic-components/中可以发现,针对此行为,有一个角度不充分的API记录。

基本上,诀窍是使用applicationRef和ViewRef注入来使angular组件代码附加到组件html

基本上,代码可以总结为:

export class ComponentBuilderService {
     constructor(private componentFactoryResolver: ComponentFactoryResolver, private injector: Injector, private appRef: ApplicationRef) {}

     buildNodeComponent(graph: Graph) {
      const factory = this.componentFactoryResolver.resolveComponentFactory(PocDataComponent);
      const inputs = [
           {
             'provide': 'entity',
             'useValue': graph
           }
       ];
       const injector = ReflectiveInjector.fromResolvedProviders(ReflectiveInjector.resolve(inputs), this.injector);
       const newLocal = factory.create(injector);
       newLocal.instance.entity = graph;
       newLocal.changeDetectorRef.detectChanges();
       this.appRef.attachView(newLocal.hostView);
       return (newLocal.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
 }

一个重要的警告说明(除了声明组件/根据需要添加到EntryComponents之外)可能是在未使用的自举组件(即AppComponent)的构造函数中添加public viewContainerRef:ViewContainerRef。 我无法查明实际原因,但有时,显然取决于我实际在何处运行构建组件(服务或其他组件),如果没有注入,它可能会失败(资源可在本文和在线中找到)