Why is my Linechart not showing endpoint data? - html

I am building an angular web app that should display data from an endpoint . I have created the service class and I got chart.js installed but the graph is showing a blank linechart even though the console is displaying the data .
could it be a bug issue or am i doing something wrong ?
this is the component.ts class
import { Component, OnInit } from '#angular/core';
import {ApiService} from '../api.service';
import {Chart} from 'chart.js';
//import { map } from 'rxjs/operators';
#Component({
selector: 'app-transactions',
templateUrl: './transactions.component.html',
styleUrls: ['./transactions.component.scss']
})
export class TransactionsComponent implements OnInit {
Linechart;
data ;
market_price_usd ;
time_date ;
constructor(private apiService : ApiService) { }
ngOnInit() {
this.apiService.dailychart()
.subscribe((data: any) => {
this.data = data;
console.log(data);
this.market_price_usd = data.market_price_usd;
this.time_date = data.timestamp;
})
this.Linechart = new Chart ('canvas', {
type : 'line',
data : {
labels : this.time_date,
datasets :[
{
data : this.market_price_usd,
borderColor: '#3cb371',
backgroundColor: "#0000FF",
fill : false
},
]
},
options : {
legend: {
display: false
},
scales : {
xAxes: [{
display: true
}],
yAxes:[{
display: true
}],
}
}
});
};
}
this is the service class : could the issues be from the endpoint that I am consuming ?
mport { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private httpclient : HttpClient ) { }
public dailychart(){
return this.httpclient.get('https://api.blockchain.info/stats') as Observable <Array<any>>
}
}
This is the component.transaction.html code :
<div class="chart-container" style="position: relative; height:40vh; width:70vw">
<canvas id="canvas">{{ Linechart }}</canvas>
</div>
I can't add pictures right now but the chart displays but without data...Just random numbers showed in the Yaxis . This is the result of the endpoint on the console :
timestamp: 1580991534000
market_price_usd: 9669.3
hash_rate: 114554768282.53265
total_fees_btc: 2465817153
.......
Thanks in advance

Related

select distinct values in an array originating from a web api with angled

I have a web api (.NET Core 3.1) that returns a json like the following:
[
{
"counterparty": "Santander",
"tradeDate": "2020-05-23T10:03:12",
"isin": "DOL110",
"typology": 0
},
{
"counterparty": "Jordan Banks",
"tradeDate": "2020-06-11T11:23:22",
"isin": "LIT250",
"typology": 0
},
{
"counterparty": "Santander",
"tradeDate": "2020-06-11T11:24:08",
"isin": "LIT300",
"typology": 0
}
]
I consume this web api with the component and angular service below. So far, I return the counterparty field of all objects.
operations.component.ts:
import { Component, OnInit } from '#angular/core';
import { OperationsService } from "./operations.service";
#Component({
selector: 'app-operations',
templateUrl: './operations.component.html',
styleUrls: ['./operations.component.css']
})
export class OperationsComponent implements OnInit {
data: any;
constructor(private operationsService: OperationsService) { }
ngOnInit(): void {
this.loadOperations();
}
loadOperations() {
return this.operationsService.getOperations().subscribe(source => this.data = source);
}
}
operations.component.html:
<div *ngFor="let item of data">
<div>{{item.counterparty}}</div>
</div>
operations.service.ts:
import { Injectable, Inject } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Injectable({
providedIn: "root"
})
export class OperationsService {
constructor(private http: HttpClient) { }
public getOperations() {
return this.http.get("https://localhost:44329/api/operations");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './user/login/login.component';
import { OperationsComponent } from './operations/operations/operations.component';
#NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
LoginComponent,
OperationsComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'api/operations', component: OperationsComponent }
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
what i need now is to apply a filter in the counterparty field to return only the distinct values, that is, without repetitions of equal values. I'm trying with ng-repeat, but i have the error:
Uncaught Error: Template parse errors:
The pipe 'unique' could not be found ("]item of data | unique: item.counterparty">
{{item.counterparty}}
")
So, how can I get the distinct values of the array? Can I do it only in component.html or do I also have to change component.ts?
I think it's best to make your this.data array unique in component.ts, then just display it in component.html.
You can use another function with promise to make data array unique, based on 'counterparty'.
// make data array unique
codeToMakeItUnique = dataArr => {
return new Promise((resolve, reject) => {
const UniArr = []
const map = new Map()
for (const item of dataArr) {
if (!map.has(item.counterparty)) {
map.set(item.counterparty, true) // set any value to Map
UniArr.push(item)
}
}
resolve(UniArr)
})
}
so altogether your component.ts will look like:
import { Component, OnInit } from '#angular/core';
import { OperationsService } from "./operations.service";
#Component({
selector: 'app-operations',
templateUrl: './operations.component.html',
styleUrls: ['./operations.component.css']
})
export class OperationsComponent implements OnInit {
data: any;
constructor(private operationsService: OperationsService) { }
ngOnInit(): void {
this.loadOperations();
}
loadOperations() {
return this.operationsService.getOperations().subscribe(async source => {
this.data = await this.codeToMakeItUnique(source)
});
// make data array unique
codeToMakeItUnique = dataArr => {
return new Promise((resolve, reject) => {
const UniArr = []
const map = new Map()
for (const item of dataArr) {
if (!map.has(item.counterparty)) {
map.set(item.counterparty, true) // set any value to Map
UniArr.push(item)
}
}
resolve(UniArr)
})
}
}
}
In your component.html you can simply call your data array itself
<div *ngFor="let item of data">
<div>{{item.counterparty}}</div>
</div>
Hope this helps.
The question isnt clear but if you want to remove duplicated value from your array, cast it as a set then back to an array. That is if the array doesnt contains complex objects
loadOperations() {
return this.operationsService.getOperations().subscribe(source => this.data = Array.from(new Set(source.map((item: any) => item.counterparty))));
}
This is going to give you [ "Santander", "Jordan Banks" ]

Angular 6: use a service to get local json data

I have a movies.json that contain a list of movies and I want to create a MoviesServices to get the data where I want.
My MoviesServices:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { HttpErrorResponse } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class MoviesService {
movies: string[];
constructor(private httpService: HttpClient) {
this.getMovies();
}
getMovies() {
this.httpService.get('../../assets/movies.json').subscribe(
data => {
this.movies = data as string[];
console.log(this.movies); // My objects array
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
console.log(this.movies); // Undefined
}
}
Firstly, I have no idea why the first console.log() works and the second not, can you tell me why ?
Here is my component where I need to get the data:
import { Component, OnInit } from '#angular/core';
import { MoviesService } from '../services/movies/movies.service';
#Component({
selector: 'app-movies',
templateUrl: './movies.component.html',
styleUrls: ['./movies.component.css']
})
export class MoviesComponent implements OnInit {
title = 'films-synopsys';
movies;
constructor(private myService: MoviesService) {}
ngOnInit() {
console.log(this.myService.movies); // Undefined
}
}
Of course this is not working. Can you tell me how must I do ? I'm newbie angular
So basically you need to return an Observable from your service and then subscribe to it from your Component. You can then assign your response to the Component property movies
Try this:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class MoviesService {
constructor(private httpService: HttpClient) { }
getMovies() {
return this.httpService.get('../../assets/movies.json');
}
}
And in your Component:
import { Component } from '#angular/core';
import { MoviesService } from './movies.service';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
title = 'films-synopsys';
movies;
constructor(private myService: MoviesService) {}
ngOnInit() {
this.myService.getMovies()
.subscribe(res => this.movies = res);
}
}
Here's a Sample StackBlitz for your ref.
Change your method to return an Observable which you can subscribe to:
import { Observable } from 'rxjs/Observable';
...
getMovies(): Observable<string []> {
this.httpService.get('../../assets/movies.json').subscribe(
data => {
this.movies = data as string[];
return this.movies;
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
}
In your calling code:
import { Subscription } from 'rxjs/Subscription';
this.myService.getMovies().subscribe(movies => {
console.log(movies); // My objects array
}
The reason the first console log works is because you are doing it within an observable's subscription. Subscriptions have three states, Next, Error, Complete and so when you console log the first time, within the subscription next state you get the value that was pushed out from the event stream.
In your component the reason why it doesn't work is due to the fact that observables are lazy, and that you need to initialize the data by calling this.myService.getMovies() first to make the subscription happen.
A better way to do this would been to pass observables around and use async pipe in the html template.

Angular 4 - service data is not persistent

I am having some trouble figuring out where I went wrong and would really appreciate some help with this.
I have a component: AudioComponent, which captures an html5 tag as a #ViewChild, then registers itself with a service: AudioService.
Here is the AudioComponent:
/* audio.component.ts */
import { Component, OnInit, Input, ViewChild } from '#angular/core';
import { IAudioOptions } from './audio-options';
export const defaultOptions: IAudioOptions = {
controls: true,
autoplay: false,
loop: false,
volume: 1.0,
startPosition: 0.0,
preload: "metadata",
muted: false
};
#Component({
selector: 'ng-audio',
templateUrl: './audio.component.html',
styleUrls: ['./audio.component.css']
})
export class AudioComponent implements OnInit {
#Input() src: any;
#Input() options: any = defaultOptions;
#Input() register: any;
#ViewChild('audio') player: any;
constructor() { }
ngOnInit() {
if (this.register) {
console.log("registering");
console.log(this.register(this));
}
}
play() {
this.player.nativeElement.play();
}
}
And the AudioService:
/* audio.service.ts */
import { Injectable } from '#angular/core';
import { AudioComponent } from './audio/audio.component';
#Injectable()
export class AudioService {
private players: AudioComponent[];
constructor() { }
register(player: AudioComponent) {
console.log("player registered");
if (this.players) {
this.players.push(player);
}
else {
console.log("initializing service");
this.players = [];
this.players.push(player);
}
return this.players;
}
getPlayers(): string[] {
var out: string[];
for (let i = 0; i < this.players.length; i++) {
out.push(this.players[i].src);
}
return out;
}
}
I'm instantiating two of the ng-audio components in my app.component.html file:
<!-- register refers to the AudioService.register function -->
<ng-audio [src]="src" [register]="register"></ng-audio>
<ng-audio [src]="src2" [register]="register"></ng-audio>
And the audio players themselves appear when I load the page.
What's puzzling is that I get the following logged to the console:
- registering
- player registered
- initializing service
- [AudioComponent]
- registering
- player registered
- initializing service // <- this should only happen the first time!
- [AudioComponent] // <- and this should now contain two elements!
For some reason, the players: AudioComponent[] property of the AudioService does not persist. So each time register() is called, it's like I'm calling it on a completely new AudioService instance!
Again, any help will be greatly appreciated. I'll be posting updates if I can figure this out.
EDIT: I've included my app.module.ts and app.component.ts files in case there's something I missed setting up the service as a provider.
AppModule:
/* app.module.ts */
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { AudioComponent } from './audio/audio.component';
import { AudioService } from './audio.service';
#NgModule({
declarations: [
AppComponent,
AudioComponent
],
imports: [
BrowserModule
],
exports: [AudioComponent],
providers: [AudioService],
bootstrap: [AppComponent]
})
export class AppModule { }
And AppComponent:
/* app.component.ts */
import { Component } from '#angular/core';
import { AudioComponent } from './audio/audio.component';
import { AudioService } from './audio.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
src = 'http://url.to/file.mp3';
src2 = 'http://url.to/another-file.mp3';
interval: any;
player: AudioComponent;
register: any;
play: any;
constructor(
private service: AudioService
) {
this.register = this.service.register;
this.play = this.service.getPlayers;
}
}

Angular2 - cannot display json objects

my boss decided to implement Angular2 into our project. I'm preety new to this technology. I'm trying to display JSON from url, but the result is not as I expected. *ngFor doesn't display any data.
This is the code:
vehicle.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class VehicleService {
constructor(private http: Http){ }
getVehicle() {
return this.http.get('https://jsonplaceholder.typicode.com/posts')
.map(res => res.json());
}}
vehicle.component.ts
import { Component } from '#angular/core';
import { VehicleService } from './vehicle.service';
#Component({
moduleId: module.id,
selector: 'vehicle-json',
templateUrl: 'vehicle.html',
providers: [ VehicleService ]
})
export class VehicleComponent {
vehicle: Vehicle[];
constructor(private vehicleService: VehicleService){
this.vehicleService.getVehicle().subscribe(vehicle => {
/*console.log(vehicle);*/this.vehicle = vehicle;
});
}
}
interface Vehicle {
id: number;
title: string;
body: string;
}
vehicle.html
<div *ngFor="let vehicle of vehicles">
<h3>{{vehicle.title}}</h3>
<p>{{vehicle.body}}</p>
</div>
test 1-2-3
The output is: "test 1-2-3". I checked if the jsons will be displayed inside the console using: console.log(vehicle); - it worked, it returns Array of Objects.
What am I doing wrong? Any ideas how to fix my code?
You have an error:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicle = vehicle;
})
but in your html you refer to let vechicle of vehicles
You should add an "s" to your this.vehicle to your subscription like so:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicles = vehicle;
})
Edit: Just forgot to meantion to change the local variable vehicle: Vehicle[] to vechicles: Vehicle, but that you figured out that yourself! ;)

Google Places with Observables in Angular2

I try to use Google Places with Observables in Angular 2.
To do that, I included the Google scripts in the index.html and then I get some inspiration with Observables from http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html
<!-- Script included in index.html -->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
You can see the whole application there: https://embed.plnkr.co/LQaag2/
I think there is an issue with the events. For example, when the user type "P", nothing appears. But if he clicks on the page or he types "a", then he will see the results of places starting by "P".
Do you have an idea why?
app/main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap'
platformBrowserDynamic().bootstrapModule(AppModule);
app/app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { JsonpModule } from '#angular/http';
import { ReactiveFormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { GoogleSearchComponent } from './google-search.component'
import { GoogleService } from './google.service';
#NgModule({
imports: [BrowserModule, JsonpModule, ReactiveFormsModule],
declarations: [AppComponent, GoogleSearchComponent],
providers: [GoogleService],
bootstrap: [AppComponent]
})
export class AppModule {}
app/app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
})
export class AppComponent { }
app/app.component.html
<google-search></google-search>
app/google-place.ts
export class GooglePlace {
constructor(public id: string,
public description: string
) {}
}
app/google-search.component.ts
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
import { GoogleService } from './google.service';
import { GooglePlace } from './google-place';
#Component({
selector: 'google-search',
template: `
<div>
<h2>Google Search</h2>
<input type="text" [formControl]="term">
<ul>
<li *ngFor="let item of items | async">{{item.description}}</li>
</ul>
</div>
`
})
export class GoogleSearchComponent {
items: Observable<Array<GooglePlace>>;
term = new FormControl();
constructor(private googleService: GoogleService) {}
ngOnInit() {
this.items = this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.switchMap(term => this.googleService.search(term));
}
}
app/google.service.ts
import { Injectable } from '#angular/core';
import { GooglePlace } from './google-place';
import { Observable } from 'rxjs/Observable';
declare var google: any;
#Injectable()
export class GoogleService {
search(term: string) {
return new Observable<GooglePlace[]>(observer => {
let result: GooglePlace[] = [];
let displaySuggestions = function(predictions: any, status: string) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
predictions.forEach(function(prediction: any) {
result.push(new GooglePlace(prediction.place_id, prediction.description));
});
observer.next(result);
observer.complete();
};
if (term) {
let service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: term }, displaySuggestions);
}
});
}
}
don't know if you're still interested but I was facing the same issue today with the bootstrap typeahead. I think I found a solution although I don't think it's the way one should do it.
Anyway, my approach was to gather the data and let the data display as if it was static.
ngOnInit(): void {
//this.recursiveTimeout();
this.items = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((term: string) => this.placesService.search(term))
.catch(() => {
this.searchFailed = true;
return Observable.of([])
}
)
this.items.subscribe(res => {
this.places = res;
//places is a string array and stores all found places , in your case it
would be an array of GooglePlace
console.log(this.places);
});
}
Then you sould be able to access the data as soon as it is available.
I just had a very similar problem with google maps. I will share here my answer, all the same, although it is so late.
The problem is because the callback function displaySuggestions of the google maps getQueryPredictions is called outside of the 'angular zone', and so angular doesn't correctly detect the changes inside of it.
The solution is relatively simple. Just 4 little changes to the app/google.service.ts. See the comments.
// import NgZone
import { Injectable, NgZone } from '#angular/core';
import { GooglePlace } from './google-place';
import { Observable } from 'rxjs/Observable';
declare var google: any;
#Injectable()
export class GoogleService {
// Inject NgZone in the constructor
constructor(private _ngZone: NgZone) {}
search(term: string) {
// save 'this' to a constant or alternatively bind it to the callback function
const self = this;
return new Observable<GooglePlace[]>(observer => {
const result: GooglePlace[] = [];
const displaySuggestions = function(predictions: any, status: string) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
console.log('GoogleService search: ', status);
return;
}
// Wrap the prediction in the zone
self._ngZone.run(function() {
predictions.forEach(function(prediction: any) {
result.push(
new GooglePlace(prediction.place_id, prediction.description)
);
});
observer.next(result);
observer.complete();
});
};
if (term) {
const service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: term }, displaySuggestions);
}
});
}
}
Edit: Perhaps you should take out your API key from the plunker, although i suppose that it might not be to serious of a problem, if it is a free one and was created exclusively for the purpose of the example...
I found an awful solution. In app/google-search.component.ts, I've added the following function :
recursiveTimeout(ms: number = 1000): void {
setTimeout(() => {
this.recursiveTimeout(ms);
}, ms);
}
Then in the ngOnInit function, I call recursiveTimeout:
ngOnInit(): void {
this.recursiveTimeout();
// ...
}
With this solution, when the user type "P" (for example):
The result will be fetched on the Google API
The result will be displayed just after the event recursiveTimeout is triggered (maximum 1000 ms)
I am open to any better solution ;)