ngAfterViewInit过早被调用。

问题描述 投票:0回答:1

我使用am4chart,我得到了一个错误,在我的控制台: html container not found. 导致这个错误的是我的angular组件的这一行。 var chart = am4core.create("graphdiv", am4charts.XYChart);

控制台中的stacktrace 。

function createChild(htmlElement, classType) {
   var htmlContainer = $dom.getElement(htmlElement);
   if (htmlContainer) {
      ...
   }
   else {
      system.log("html container not found");
      throw new Error("html container not found");
   }
}

所以基本上我的理解是,这行......是在图形div元素存在之前执行的。var chart = am4core.create("graphdiv", am4charts.XYChart); 是在DOM中graphdiv元素存在之前执行的,因为它没有找到graphdiv的HTML元素。

所以我所做的是,我把我的代码复制粘贴到了 ngAfterViewInit angular函数,以确保创建am4chart图表的脚本是在运行脚本之前执行的,以确保DOM存在。

我的afterViewInit函数 。

ngAfterViewInit(): void {
    console.log("CREATE GRAPH AFTER VIEW INIT")
    this.createGraph();
}

但我看到的是 console.log("CREATE GRAPH AFTER VIEW INIT")实际上是在DOM完全渲染之前执行的,所以我所做的并没有让我的错误消失。html container not found

createGraph()。

createGraph() {

    console.log("CREATE GRAAAAPH");

    // Create chart instance
    am4core.ready(function() {

      var chart = am4core.create("graphdiv", am4charts.XYChart);
      chart.numberFormatter.numberFormat = this.currencyBefore + "#,####,###.##" + this.currencyAfter;

      chart.data = [];
      var cumul = 0;

      for (var i = 0; i < 37; i++) {
        if (i == 0) {
          chart.data.push({ "month": "", "units": 0 });
        } 
        else if (i == 1) {
          cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear1 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
          chart.data.push({ "month": "M" + i, "units": cumul });
        } 
        else if (i == 13) {
          cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear2 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
          chart.data.push({ "month": "M" + i, "units": cumul });
        } 
        else if (i == 25) {
          cumul = cumul + this.AppComponent.activeDetailedResults.prices.upfrontYear3 + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
          chart.data.push({ "month": "M" + i, "units": cumul });
        } 
        else {
          cumul = cumul + this.AppComponent.activeDetailedResults.prices.monthlyPrice;
          chart.data.push({ "month": "M" + i, "units": cumul });
        }
      }

      // Create axes
      let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
      categoryAxis.dataFields.category = "month";
      categoryAxis.renderer.labels.template.disabled = true
      categoryAxis.title.text = "Time (36 months)";

      let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
      valueAxis.renderer.labels.template.disabled = false;

      // Create series
      var series2 = chart.series.push(new am4charts.LineSeries());
      series2.name = "Units";
      series2.stroke = am4core.color("#551A8B");
      series2.strokeWidth = 3;
      series2.dataFields.valueY = "units";
      series2.dataFields.categoryX = "month";
      series2.fillOpacity = 0.5;
    });
  }

模板 :

<mat-card class="startcard">
   <p class="mat-title">Cumulative expenses: </p>
   <mat-card-content style="text-align: center;">
      <div fxLayout="row" fxLayoutAlign="space-around center">
         <div id="graphdiv"></div>
      </div>
   </mat-card-content>
</mat-card>
angular dom graph
1个回答
1
投票

所以问题是在创建组件时元素不可见,因为你在等待API调用。你可以让 ViewChild 一个设定器。

如果这是你的模板,

<mat-card class="startcard">
   <p class="mat-title">Cumulative expenses: </p>
   <mat-card-content style="text-align: center;">
      <div fxLayout="row" fxLayoutAlign="space-around center">
         <div #graphdiv></div>
      </div>
   </mat-card-content>
</mat-card>

你可以把你的组件做成下面这个样子。

private _div?: HTMLElement;

@ViewChild('graphdiv')
set graphDiv(div: ElementRef<HTMLElement>) {
  if (div && div.nativeElement && this._div !== div.nativeElement) {
    this._div = div.nativeElement;
    this.createGraph();
  }
}

createGraph() {
  am4core.ready(() => {
    const chart = am4core.create(this._div, am4charts.XYChart);
  });
}

这样你就不需要再去做了。ngAfterViewInit 钩子或API调用后。它将自动完成


0
投票

你可以试着把你的代码移到 ngAfterViewChecked 的方法。作为另一种尝试是使用 setTimeout 用0时间和你的代码里面。

© www.soinside.com 2019 - 2024. All rights reserved.