我得到了很多变量未定义,并在他们不应该运行的时候运行。我最好的猜测是,这与我调用API的方式有关。
完整代码- https://fennzo-advantageapi-emn793znarg.ws-us93.gitpod.io/
-
当我运行程序时,控制台语句不会在chrome上打印,而是在边缘上??
-
当我开始问题时,当我尝试读取csv时,我在app.component.ts ngOnInit()中得到错误
中。ERROR TypeError: Cannot read properties of undefined (reading 'trim')
。csv不是空的,此方法按预期工作,将csv加载到数组 -
当我点击查看股票符号,图表显示如预期,但我得到
loader.js:98 ERROR Error: Uncaught (in promise): TypeError: Cannot use 'in' operator to search for 'Time Series (5min)' in undefined
。在调试中,我可以看到这行console.log("data", this.data);
在chart.componenet.ts中总共运行了3次,当app.component.ts generate_stock_chart
中的api调用准备好数据时,它应该只运行一次,然后将数据发送到chart.component.ts -
同样的问题在3)适用于外汇
app.component.ts
import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'Homework4';
starter_url = 'https://www.alphavantage.co/query?function=';
stock_search_url = 'SYMBOL_SEARCH&keywords=';
stock_symbol = '';
url = '';
api_key = '5QKIUHUZF5KPBKR8';
show_chart = false;
chartData: Object = [];
searchable = ''
stock_search_results: any[] = [];
forex_list: any[] = [];
crypto_list: any[] = [];
from_currency = ''
to_currency = ''
currency_info :Object = [];
forex_search_result: any[] = [];
constructor(private http: HttpClient) { } // used to access the service methods
generate_stock_chart(){
// console.log("generateStockUrl() called");
this.url = this.starter_url + 'TIME_SERIES_INTRADAY&symbol=' + this.stock_symbol + '&interval=5min&apikey=' + this.api_key;
// console.log("URL", this.url)
this.http.get(this.url).subscribe((data) => {
this.chartData = data;
console.log("CHART DATA: ", this.chartData);
this.show_chart = true;
});
}
forex_search(event: any) {
// console.log("forex list2", this.forex_list)
let input = event.target.value;
// console.log("input forex", input)
this.forex_search_result = this.forex_list.filter((match: any) => {
return match.code.toLowerCase().startsWith(input.toLowerCase()) ||
match.name.toLowerCase().startsWith(input.toLowerCase())
});
}
symbol_search(event: any) {
let input = event.target.value;
let final_search_url = this.starter_url + this.stock_search_url + input + '&apikey=' + this.api_key;
// console.log("url: ", final_search_url);
// console.log("input: ", input);
this.http.get(final_search_url).subscribe((data: any) => {
this.stock_search_results = data.bestMatches.map((match: any) => {
return {
symbol: match['1. symbol'],
name: match['2. name']
};
});
});
console.log(this.stock_search_results)
}
ngOnInit(){
this.http.get('assets/csv/digital_currency_list.csv', {responseType: 'text'}).subscribe(data => {
const rows = data.split('n');
rows.shift()
this.crypto_list = rows.map((row : any) => {
const cols = row.split(',');
return {
code: cols[0],
name: cols[1].trim()
}
})
})
this.http.get('assets/csv/physical_currency_list.csv', {responseType: 'text'}).subscribe(data => {
const rows = data.split('n');
rows.shift()
rows.map((row : any) => {
const cols = row.split(',');
this.forex_list.push({code: cols[0], name: cols[1].trim()})
})
console.log("forex list", this.forex_list)
})
}
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_currency=' + this.to_currency + '&apikey=' + this.api_key;
this.http.get(chart_url).subscribe((data) => {
this.chartData = data;
console.log("CHART DATA: ", this.chartData);
});
this.http.get(exchange_rate_url).subscribe((data) => {
this.currency_info = data;
console.log("currency_info", this.currency_info)
this.show_chart = true;
})
}
}
app.component.html
<h1>Click the button to view the chart of the commodity</h1>
<h2>Commodities</h2>
<h2>Technical indicators</h2>
<nav>
<h2>Stock symbol</h2>
<mat-form-field class="example-full-width">
<input matInput placeholder="Stock symbol" [(ngModel)]="stock_symbol" [matAutocomplete]="auto1" (input)="symbol_search($event)">
<mat-autocomplete #auto1="matAutocomplete" >
<mat-option *ngFor="let result of stock_search_results" [value]="result.symbol">
<span>{{ result.symbol}}</span> | <span>{{ result.name}}</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
<button (click)="generate_stock_chart()" [routerLink]="'/data/' + stock_symbol">View</button>
<h2>Forex</h2>
<div style="display: flex;">
<mat-form-field class="example-full-width" style="margin-right: 16px;">
<input matInput placeholder="From currency" [(ngModel)]="from_currency" [matAutocomplete]="auto2" (input)="forex_search($event)">
<mat-autocomplete #auto2="matAutocomplete">
<mat-option *ngFor="let result of forex_search_result" [value]="result.code">
<span>{{ result.code}}</span> | <span>{{ result.name}}</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="example-full-width">
<input matInput placeholder="To currency" [(ngModel)]="to_currency" [matAutocomplete]="auto3" (input)="forex_search($event)">
<mat-autocomplete #auto3="matAutocomplete">
<mat-option *ngFor="let result of forex_search_result" [value]="result.code">
<span>{{ result.code}}</span> | <span>{{ result.name}}</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
<button (click)="generate_forex_chart()" [routerLink]="'/data/' + from_currency + 'to' + to_currency" >View</button>
</div>
</nav>
<div *ngIf="show_chart">
<app-chart [data]="chartData "></app-chart>
<app-chart [forex_data]="currency_info"></app-chart>
</div>
<router-outlet></router-outlet>
chart.component.ts
import { Component, Input, OnInit } from '@angular/core';
declare var google: any;
@Component({
selector: 'app-chart',
templateUrl: './chart.component.html',
styleUrls: ['./chart.component.css']
})
export class ChartComponent {
@Input() data: any;
chart_name = '';
timeSeriesData = [];
@Input() forex_data: any;
forex_info = '';
constructor() {
this.initalize()
}
initalize(): void {
google.charts.load('current', { packages: ['corechart'] });
google.charts.setOnLoadCallback(() => this.drawChart());
}
drawChart(): void {
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');
dataTable.addRows(this.parseChartData());
const chartOptions = {
title: this.chart_name,
height: 500,
width: 900,
legend: { position: 'bottom' }
};
const chart = new google.visualization.CandlestickChart(document.getElementById('chartContainer'));
chart.draw(dataTable, chartOptions);
}
parseChartData(): any[] {
const timeSeries = [];
console.log("data", this.data);
console.log("forex_data", this.forex_data)
// stock
if ('Time Series (5min)' in this.data){
this.chart_name = this.data["Meta Data"]["2. Symbol"] + ' stock price'
this.timeSeriesData = this.data['Time Series (5min)'];}
// forex
else if ('Time Series FX (Daily)' in this.data){
this.forex_info = "1 " + this.data["Meta Data"]["2. From Symbol"] + " to " + this.data["Meta Data"]["3. To Symbol"] + this.forex_data["Realtime Currency Exchange Rate"]["5. Exchange Rate"] + " " + this.forex_data["Realtime Currency Exchange Rate"]["6. Last Refreshed"] + " " + this.forex_data["Realtime Currency Exchange Rate"]["7. Time Zone"]
this.chart_name = this.data["Meta Data"]["2. From Symbol"] + ' To ' + this.data["Meta Data"]["3. To Symbol"]
this.timeSeriesData = this.data['Time Series FX (Daily)'];
console.log("forex_info", this.forex_info)
console.log("chart_name", this.chart_name)
}
else if('Error Message'){
this.forex_info = "Not available! Please choose another option"
}
for (const key in this.timeSeriesData) {
if (this.timeSeriesData.hasOwnProperty(key)) {
const time = new Date(key).toISOString();
const open = parseFloat(this.timeSeriesData[key]['1. open']);
const high = parseFloat(this.timeSeriesData[key]['2. high']);
const low = parseFloat(this.timeSeriesData[key]['3. low']);
const close = parseFloat(this.timeSeriesData[key]['4. close']);
timeSeries.push([time, open, high, low, close]);
}
}
return timeSeries;
}
}
试着调试,发现chart.component.ts收到数据之前,导致变量未定义
- 这个问题是因为您的CSV数据(资产中的两个文件)在末尾包含空行。只要删除它们,这个错误就会消失。
- 这个问题是因为你试图在angular传递数据之前在构造函数中构建图表。
- 所以删除你在ChartComponent 中的构造函数
- 在ChartComponent 中实现OnChanges
export class ChartComponent implements OnChanges {
...
ngOnChanges(changes: SimpleChanges): void {
if (changes['data']) {
this.initalize();
}
}