0

I'm getting a lot of my variables undefined and ran at times when they shouldn't run. My best guess is that it is related to the way I make the API call.

Full code - https://fennzo-advantageapi-emn793znarg.ws-us93.gitpod.io/

  1. When I run the program, the console statements doesn't get printed on chrome but on edge??

  2. When I start the problem I get the error ERROR TypeError: Cannot read properties of undefined (reading 'trim') in app.component.ts ngOnInit() when I try to read csv. The csv are not empty and this method works as expected to load the csv into the arrays

  3. When I click view for Stock symbol, the chart displays as expected, but I get loader.js:98 ERROR Error: Uncaught (in promise): TypeError: Cannot use 'in' operator to search for 'Time Series (5min)' in undefined. In debug, I can see this line console.log("data", this.data); in chart.componenet.ts ran 3 times in total when it should only run once when the api call in app.component.ts generate_stock_chart has the data ready which then sends the data to chart.component.ts

  4. The same problem in 3) applies for forex

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;
  }
}

Tried debugging and found out chart.component.ts receives data before it's suppose to and resulting in variables to be undefined

3

1 Answer 1

0
  1. This issue is because your CSV data (both files in assets) contains empty lines at the end. Just remove them, and this error will go away.
  2. This issue is because you are trying to build a chart in constructor before the angular passes the data.
  • So remove your constructor in ChartComponent
  • Implement OnChanges in ChartComponent
export class ChartComponent implements OnChanges {
...
 ngOnChanges(changes: SimpleChanges): void {
    if (changes['data']) {
      this.initalize();
    }
  }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.