I am trying to create a table of stock quotes using the IEX trading api. However, I am having issues trying to hook it up to the datasource. I am able to use an ngfor and display the data, but data is not being displayed when trying to use the table. I am not sure what else to try. I was thinking it could be how I am receiving the data from the API. In the service class, I try to convert it to an array, so it can work with the table.
@Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.css']
})
export class TableComponent implements OnInit {
displayedColumns: string[] = ['symbol'];
quote:Quote[] = [];
dataSource = new QuoteDataSource(this.stocksummary);
constructor(private stocksummary:StocksummaryService) { }
ngOnInit() {
// this.stocksummary.getStocks().subscribe(t => {this.quote = t});
// console.log(this.quote);
}
}
export class QuoteDataSource extends DataSource<any> {
constructor(private stocksummary:StocksummaryService)
{
super();
}
connect(): Observable<Quote[]>
{
var data = this.stocksummary.getStocks();
console.log(data);
return data;
}
disconnect(){}
}
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
}
@Injectable({
providedIn: 'root'
})
export class StocksummaryService {
quote:Quote[] = [];
constructor(private http:HttpClient) { }
getStocks():Observable<Quote[]> {
this.http.get<Quote>("https://api.iextrading.com/1.0/stock/market/batch?symbols=AABA,AAPL,ABBV&types=quote")
.subscribe(data => {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this.quote.push(data[key]["quote"]);
}
}
});
return observableOf(this.quote);
}
}
export interface Quote {
symbol?: string;
companyName?: string;
primaryExchange?: PrimaryExchange;
sector?: string;
calculationPrice?: CalculationPrice;
open?: number;
openTime?: number;
close?: number;
closeTime?: number;
high?: number;
low?: number;
latestPrice?: number;
latestSource?: LatestSource;
latestTime?: LatestTime;
latestUpdate?: number;
latestVolume?: number;
iexRealtimePrice?: null;
iexRealtimeSize?: null;
iexLastUpdated?: null;
delayedPrice?: number;
delayedPriceTime?: number;
extendedPrice?: number;
extendedChange?: number;
extendedChangePercent?: number;
extendedPriceTime?: number;
previousClose?: number;
change?: number;
changePercent?: number;
iexMarketPercent?: null;
iexVolume?: null;
avgTotalVolume?: number;
iexBidPrice?: null;
iexBidSize?: null;
iexAskPrice?: null;
iexAskSize?: null;
marketCap?: number;
peRatio?: number | null;
week52High?: number;
week52Low?: number;
ytdChange?: number;
}
export enum CalculationPrice {
Close = "close",
}
export enum LatestSource {
Close = "Close",
}
export enum LatestTime {
February82019 = "February 8, 2019",
January292019 = "January 29, 2019",
}
export enum PrimaryExchange {
NASDAQGlobalMarket = "NASDAQ Global Market",
NYSEArca = "NYSE Arca",
NasdaqGlobalSelect = "Nasdaq Global Select",
NewYorkStockExchange = "New York Stock Exchange",
}
<table mat-table [dataSource]="dataSource"
class="mat-elevation-z4" >
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> symbol </th>
<td mat-cell *matCellDef="let item">
{{item.symbol}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns:
displayedColumns;"></tr>
</table>
The problem you are facing is due to the fact that you are subscribing to your HTTP request in your service, but then return the data outside of that subscription (when the request most likely hasn't been executed yet).
I would write it like this:
public getStocks(): Observable<Quote[]> {
return this.http.get<Quote>("https://api.iextrading.com/1.0/stock/market/batch?symbols=AABA,AAPL,ABBV&types=quote")
.pipe(map(data => {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this.quote.push(data[key]["quote"]);
}
}
return this.quote;
}));
}
Here we make the request, use pipe
and map
to transform your data the way you want it, but don't actually subscribe to it, that will be the job of the component/datasource. We just return that Observable
and are good to go.
Also in your ngOnInit
you are making a similar mistake again, you are subscribing to the Observable
and without "waiting" for the response you are trying to log the return value, it should be like this:
ngOnInit() {
this.stocksummary.getStocks().subscribe(t => {
this.quote = t;
console.log(this.quote);
});
}
Here is a working stackblitz that shows a working version of your code.