You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular项目API调用后变量未定义及多端异常问题排查

Angular项目问题修复方案

问题清单

  • Chrome控制台无日志输出,Edge可正常打印
  • 项目启动时,ngOnInit读取CSV文件出现ERROR TypeError: Cannot read properties of undefined (reading 'trim')
  • 点击股票"View"按钮后图表显示,但报错loader.js:98 ERROR Error: Uncaught (in promise): TypeError: Cannot use 'in' operator to search for 'Time Series (5min)' in undefined,且chart.component.ts中console.log("data", this.data);执行3次
  • 外汇模块存在与上述第三点相同的异常

逐个问题修复

1. Chrome控制台无日志输出

  • 检查Chrome控制台过滤设置:确保未勾选"Hide network"、"Warnings"或"Errors",根据需求调整"Preserve log"状态
  • 取消代码中被注释的console.log语句,比如app.component.ts内generate_stock_chart、symbol_search方法里的注释日志

2. CSV读取时trim报错

原因:CSV文件可能存在空行,拆分后cols[1]为undefined,调用trim()触发错误。

修改app.component.ts的ngOnInit方法:

ngOnInit(){
  this.http.get('assets/csv/digital_currency_list.csv', {responseType: 'text'}).subscribe(data => {
    const rows = data.split('\n').filter(row => row.trim() !== ''); // 过滤空行
    rows.shift();
    this.crypto_list = rows.map((row : any) => {
      const cols = row.split(',');
      return {
        code: cols[0]?.trim() || '', // 可选链避免undefined
        name: cols[1]?.trim() || ''
      };
    });
  });

  this.http.get('assets/csv/physical_currency_list.csv', {responseType: 'text'}).subscribe(data => {
    const rows = data.split('\n').filter(row => row.trim() !== ''); // 过滤空行
    rows.shift();
    rows.forEach((row : any) => {
      const cols = row.split(',');
      this.forex_list.push({
        code: cols[0]?.trim() || '',
        name: cols[1]?.trim() || ''
      });
    });
    console.log("forex list", this.forex_list);
  });
}

3. Chart组件提前接收数据导致未定义错误(含外汇模块)

原因:

  • Chart组件初始化时立即调用drawChart,此时@Input数据尚未从API返回,导致undefined
  • app.component.html渲染了两个app-chart实例,加上数据更新时的重绘,导致日志多次输出
  • 外汇模块的两个API请求异步执行,可能先触发show_chart但数据未完全加载

修复步骤:

(1)优化模板渲染,合并Chart组件实例

修改app.component.html的chart渲染部分:

<div *ngIf="show_chart">
  <app-chart [stockData]="chartData" [forexInfo]="currency_info"></app-chart>
</div>
(2)修改Chart组件,监听数据变化并确保有效再绘制

更新chart.component.ts:

import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core';

declare var google: any;

@Component({
  selector: 'app-chart',
  templateUrl: './chart.component.html',
  styleUrls: ['./chart.component.css']
})
export class ChartComponent implements OnInit, OnChanges {

  @Input() stockData: any;
  @Input() forexInfo: any;
  chart_name = '';
  timeSeriesData: any[] = [];
  forex_info = '';

  ngOnInit(): void {
    google.charts.load('current', { packages: ['corechart'] });
    google.charts.setOnLoadCallback(() => this.drawChart());
  }

  ngOnChanges(changes: SimpleChanges): void {
    // 数据更新时重新绘制图表
    if ((changes['stockData'] && changes['stockData'].currentValue) || 
        (changes['forexInfo'] && changes['forexInfo'].currentValue)) {
      if (google.visualization) {
        this.drawChart();
      }
    }
  }

  drawChart(): void {
    // 无有效数据时终止执行
    if (!this.stockData && !this.forexInfo) return;

    const dataTable = new google.visualization.DataTable();
    dataTable.addColumn('string', 'Time');
    dataTable.addColumn('number', 'Open');
    dataTable.addColumn('number', 'High');
    dataTable.addColumn('number', 'Low');
    dataTable.addColumn('number', 'Close');
    
    const timeSeries = this.parseChartData();
    if (timeSeries.length > 0) {
      dataTable.addRows(timeSeries);
    }

    const chartOptions = {
      title: this.chart_name,
      height: 500,
      width: 900,
      legend: { position: 'bottom' }
    };

    const chartContainer = document.getElementById('chartContainer');
    if (chartContainer) {
      const chart = new google.visualization.CandlestickChart(chartContainer);
      chart.draw(dataTable, chartOptions);
    }
  }

  parseChartData(): any[] {
    const timeSeries = [];
    this.timeSeriesData = [];
    this.chart_name = '';
    this.forex_info = '';

    // 处理股票数据
    if (this.stockData && 'Time Series (5min)' in this.stockData) {
      this.chart_name = `${this.stockData["Meta Data"]["2. Symbol"]} stock price`;
      this.timeSeriesData = this.stockData['Time Series (5min)'];
    } 
    // 处理外汇数据
    else if (this.stockData && 'Time Series FX (Daily)' in this.stockData && this.forexInfo) {
      const meta = this.stockData["Meta Data"];
      const exchangeRate = this.forexInfo["Realtime Currency Exchange Rate"];
      this.forex_info = `1 ${meta["2. From Symbol"]} = ${exchangeRate["5. Exchange Rate"]} ${exchangeRate["4. To Currency Code"]} (Last refreshed: ${exchangeRate["6. Last Refreshed"]} ${exchangeRate["7. Time Zone"]})`;
      this.chart_name = `${meta["2. From Symbol"]} To ${meta["3. To Symbol"]}`;
      this.timeSeriesData = this.stockData['Time Series FX (Daily)'];
    }
    // 处理错误情况
    else if (this.stockData && 'Error Message' in this.stockData) {
      this.forex_info = "Not available! Please choose another option";
      return timeSeries;
    }

    // 转换时间序列数据
    for (const key in this.timeSeriesData) {
      if (this.timeSeriesData.hasOwnProperty(key)) {
        const entry = this.timeSeriesData[key];
        timeSeries.push([
          new Date(key).toISOString(),
          parseFloat(entry['1. open']),
          parseFloat(entry['2. high']),
          parseFloat(entry['3. low']),
          parseFloat(entry['4. close'])
        ]);
      }
    }

    return timeSeries;
  }
}
(3)优化API请求逻辑,确保数据完整后再显示图表

修改app.component.ts的generate_stock_chart和generate_forex_chart方法:

import { forkJoin } from 'rxjs';

// ... 其他代码

generate_stock_chart(){
  this.url = `${this.starter_url}TIME_SERIES_INTRADAY&symbol=${this.stock_symbol}&interval=5min&apikey=${this.api_key}`;

  this.http.get(this.url).subscribe((data: any) => {
    if (data['Error Message']) {
      console.error(data['Error Message']);
      return;
    }
    this.chartData = data;
    this.show_chart = true; // 数据有效再显示图表
  }, error => {
    console.error('API请求失败:', error);
  });
}

generate_forex_chart() {
  const chart_url = `${this.starter_url}FX_DAILY&from_symbol=${this.from_currency}&to_symbol=${this.to_currency}&apikey=${this.api_key}`;
  const exchange_rate_url = `${this.starter_url}CURRENCY_EXCHANGE_RATE&from_currency=${this.from_currency}&to_symbol=${this.to_currency}&apikey=${this.api_key}`;

  // 等待两个API请求都完成后再更新数据和显示图表
  forkJoin([
    this.http.get(chart_url),
    this.http.get(exchange_rate_url)
  ]).subscribe(([chartData, currencyInfo]: any[]) => {
    if (chartData['Error Message'] || currencyInfo['Error Message']) {
      console.error('API请求错误:', chartData['Error Message'] || currencyInfo['Error Message']);
      return;
    }
    this.chartData = chartData;
    this.currency_info = currencyInfo;
    this.show_chart = true;
  }, error => {
    console.error('API请求失败:', error);
  });
}

内容的提问来源于stack exchange,提问作者bryan lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:49:55