I have an Angular 7 project with a PHP Laravel API backend that is returning json from get requests.
return Response::json($genres);
I'm using httpClient in a service which is being called from a component (see both below). When I console log the data it is a string, not a json object. Also I am unable to access any of the properties that it has because it is just a long string.
In most online examples people used map and then pipe but those are both deprecated now and apparently httpClient just returns JSON as default but that is not what appears to be happening in this case.
Could someone give me a solution to this? I need access to the data in the response as JSON.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http:HttpClient) { }
getGenres(){
return this.http.get('http://www.localhost:7888/api/genres', this.genre);
}
}
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../../services/api.service';
#Component({
selector: 'app-genres',
templateUrl: './genres.component.html',
styleUrls: ['./genres.component.css']
})
export class GenresComponent implements OnInit {
constructor(private apiService: ApiService) { }
ngOnInit() {
// make http request to http://www.localhost:7888/api/genres
this.apiService.getGenres().subscribe(data => {
console.log(data);
},
error => {
console.log(error);
});
}
}
Related
I am calling HTTPS API from Angular service deployed in http server by the following code.
this.chatbotUrl = "https://something.com/api";
getDashBoardData(): Observable<any> {
return this.http.get<IContainer>(this.chatbotUrl+"/chatbot/get-dashboard-data").pipe(
map((response) => (response ? response : {})),
catchError( this.handleError )
);
}
But when I am calling this API, then I am getting this error, "Http failure response for https://something.com/api/chatbot/get-dashboard-data: 0 Unknown Error". The following error is also get.
GET https://something.com/api/chatbot/get-time-wise-traffic/7 net::ERR_CERT_COMMON_NAME_INVALID
How can I call https API from Angular service deployed in http server?
I suppose you have not configured the API properly,check whether the site requires any key to get accessed.Here I have provided the component.ts file and service file for the API I am working with for your reference.
If CORS error try adding CORS extension to your browser;else clear your cache and run your code again.
Component.ts:
import { Component, OnInit } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
import { YoutubeService } from '../youtube.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
Name:any;
details: any;
info:any;
display!:boolean;
constructor(private service:YoutubeService,public sanitizer: DomSanitizer) { }
ngOnInit(): void {
this.service.GetVideos().subscribe((res:any)=> {
this.info= res as any
this.info=this.info.items;
console.log(this.info);
this.display=true
});
}
onSubmit() {
this.service.GetSearch(this.Name).subscribe(res=> {
this.details= res as any
this.details=this.details.items;
// this.details.forEach((function.this.details.i) => {
// ele
// });
console.log(this.details);
this.display=true
});
}
}
Service:
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { GoogleLoginProvider } from 'angularx-social-login';
#Injectable({
providedIn: 'root'
})
export class YoutubeService {
private APIURL = "https://youtube.googleapis.com/youtube/v3/";
private APIKEY ="AIzaSyB40HaKwd0VggftBq8R9sEwQx_NG5xOOWc";
constructor(private http:HttpClient) { }
public GetSearch(name:string)
{
console.log(name)
return this.http.get(this.APIURL+"search?part=snippet&key="+this.APIKEY+"&q="+name+"&type=video");
}
When trying to get the data from an observable I am getting this error from the console.
My code is as follows
Anglar Service - service.ts
import { Injectable } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
#Injectable({
providedIn: 'root'
})
export class ViewReportService {
constructor(private firestore: AngularFirestore) { }
getReport = (myDocument) =>
this.firestore.collection("report").doc(myDocument).get()
}
component ts.
import { Component, OnInit } from '#angular/core';
import { ViewReportService } from '../shared/view-report.service';
import { Observable } from 'rxjs';
#Component({
selector: 'app-view-report',
templateUrl: './view-report.component.html',
styleUrls: ['./view-report.component.scss']
})
export class ViewReportComponent implements OnInit {
document= [];
document$ : Observable<any>;
constructor(private service: ViewReportService) { }
ngOnInit(){
let documentID = "----"
//Get the Data from the view-report service
this.document$ = this.service.getReport(documentID);
}
}
on my HTML View
<table *ngIf="document$ | async as document">
<pre>{{document.name}}</pre>
It sounds like you have an circular object structure, which then can't be stored in the database. Remember: Firestore documents can only contain JSON data, and not all JavaScript objects are valid JSON. For example: JavaScript objects may contain function definitions, which are not valid in JSON.
The simplest way to convert a JavaScript object to JSON, is JSON.parse(JSON.stringify(object)). You'll need to do this in the place where you write the object to the database.
I'm still new to Angular and learning Angular 8 currently.
I'm trying to create a simple API communication Service to load the data needed for display. I have a main Component with a sub-Component and both need to fetch data to load.
I've tried following several tutorials but my common issue is that the Component loading is happening before the API HTTP request is returned, leading to undefined data.
My current API Service uses HttpClient to communicate with the API
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
getUserFeed(id: number): Observable<Post[]> {
return this.http
.get<Post[]>(`${API_URL}/feed`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
getProfile(id: number): Observable<Profile> {
return this.http
.get<Profile>(`${API_URL}/profile/${id}`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
handleError(error: any) {
let errorMessage: string;
// Set error message
(error.error instanceof ErrorEvent) ?
errorMessage = error.error.message :
errorMessage = `Error Code: ${error.code}\nMessage: ${error.message}`;
console.log(errorMessage);
return throwError(errorMessage);
}
}
The API should be returning an array of Posts I've defined.
I call this in my component as
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user/user.service';
import { ApiService } from '../api/api.service';
import { User } from '../user';
import { Post } from '../Post';
#Component({
selector: 'app-feed',
templateUrl: './feed.component.html',
styleUrls: ['./feed.component.css'],
})
export class FeedComponent implements OnInit {
posts: Post[] = [];
user: User;
post: Post;
constructor(private userService: UserService) {
this.user = this.userService.user;
}
public ngOnInit() {
this.userService.getUserFeed(this.user.id).subscribe((feed) => {
this.posts = feed;
console.log(this.posts);
});
}
}
My Component HTML should loop through these posts and pass the post to the sub-Components I have
<div *ngIf="posts.length">
<mat-list *ngFor="let post of posts">
<!-- Post Display -->
<app-post-display [post]=post></app-post-display>
<!-- Post Interaction Row -->
<app-post-interaction-bar [post]=post></app-post-interaction-bar>
<!-- Comment Preview -->
<app-comment-preview [post]=post></app-comment-preview>
<mat-divider></mat-divider>
</mat-list>
</div>
So far it seems to be picking up the posts for the main component as expected. The issue is in the sub-Component app-post-display which performs a similar action getting the post author from the post.authorId property.
I've declared an author and I've placed the code to fetch the author data in ngOnInit but I consistently get ERROR TypeError: Cannot read property 'id' of undefined in the console, no matter what I try it seems that the Component is trying to display before the author is fetched.
What do I need to adjust to have the author data fetched before the Component display is loaded
import { Component, Input, OnInit } from '#angular/core';
import { UserService } from '../user/user.service';
import { User } from '../user';
import { Post } from '../post';
import { Profile } from '../profile';
import { ApiService } from '../api/api.service';
#Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.css'],
})
export class PostDisplayComponent implements OnInit {
#Input() post: Post;
user: User;
author: Profile;
constructor(private userService: UserService, private backend: BackendService) {
this.user = this.userService.user;
}
ngOnInit() {
this.backend.getProfile(this.post.authorId).subscribe((profile) => {
this.author = profile;
console.log(this.author);
});
}
}
ngOnInit of the Child Component will run only once. Also, you can't expect it to get the post defined initially.
To fix it, you should move your call to ngOnChanges and check if post is defined first. Here, give this a try:
import { Component, Input, OnChanges } from '#angular/core';
import { UserService } from '../user/user.service';
import { User } from '../user';
import { Post } from '../post';
import { Profile } from '../profile';
import { ApiService } from '../api/api.service';
#Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.css'],
})
export class PostDisplayComponent implements OnChanges {
#Input() post: Post;
user: User;
author: Profile;
constructor(
private userService: UserService,
private backend: BackendService
) {
this.user = this.userService.user;
}
ngOnChanges() {
if (this.post) {
this.backend.getProfile(this.post.authorId).subscribe((profile) => {
this.author = profile;
console.log(this.author);
});
}
}
}
Alternatively, you can do that in your Parent Component:
<div *ngIf="posts">
<mat-list *ngFor="let post of posts">
<!-- Post Display -->
<app-post-display [post]=post></app-post-display>
<!-- Post Interaction Row -->
<app-post-interaction-bar [post]=post></app-post-interaction-bar>
<!-- Comment Preview -->
<app-comment-preview [post]=post></app-comment-preview>
<mat-divider></mat-divider>
</mat-list>
</div>
Just make sure you're not initializing the posts with an empty array initially though.
The best answer I found for my problem was actually using a resolver before the page is directed to (https://angular.io/api/router/Resolve).
This allowed the data to be loaded before the page was fully rendered, hence no errors.
I have a very simple API call when clicking on minister router link. It displays some data when minister page is open. But I see whenever I came back to that page either from the homepage or any other page the API keeps loading again.
minister.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiReadService } from "../apiReadService.service";
interface mydata{
allMinisters: Object
}
#Component({
selector: 'app-ministers',
templateUrl: './ministers.component.html',
styleUrls: ['./ministers.component.scss']
})
export class MinistersComponent implements OnInit {
allData:Object = [];
constructor(private apiRead: ApiReadService) {
}
ngOnInit(){
this.apiRead.getData().subscribe(data=>{
this.allData = data.allMinisters;
});
}
}
apiReadSerivce.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/Http';
#Injectable({
providedIn: 'root'
})
export class ApiReadService {
constructor(private http: HttpClient) { }
getData(){
return this.http.get('http://localhost:8081/allMinisters')
}
}
The simplest way - if you only ever want the data to load once is something like this:
import { shareReplay } from 'rxjs/operators';
export class ApiReadService {
constructor(private http: HttpClient) { }
ministers$ = this.http.get('http://localhost:8081/allMinisters')
.pipe(shareReplay(1))
getData() {
return this.ministers$;
}
}
Once the results have been returned once it will get 'cached' by the shareReplay(1) and that same value returned each time.
I am using Angular 5 and trying to get some data from JsonPlaceholder.
First I created the service, then added:
import { HttpClientModule } from '#angular/common/http';
This is the service code:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class DataService {
private ROOT_URL = 'http://jsonplaceholder.typicode.com';
constructor(private http: HttpClient) {}
getPosts() {
this.http.get(`${this.ROOT_URL}/posts`).subscribe(data => {
return data;
});
}
}
And finally, on my app.component.ts:
import { Component, OnInit } from '#angular/core';
import { DataService } from '../../services/data.service';
#Component({
selector: 'app-root',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class AppComponent implements OnInit {
data;
constructor(private dataService: DataService) {
this.data = dataService.getPosts();
console.log(this.data;
}
ngOnInit() {
}
}
On the console it's just returning 'Undefined'
What I'm I doing wrong?
Don't subscribe on the service, return the observable and subscribe to it on the component. Because it is asynchronous your data variable on the component will be undefined because you assigned before the http request could resolve a value.
On the service:
getPosts() {
return this.http.get(`${this.ROOT_URL}/posts`);
}
On the coponent:
ngOnInit() {
this.dataService.getPosts().subscribe(posts => this.posts = posts);
}
Try following code snippet.
You are getting undefined because you assigning the data before the http request could resolve a value. Remove the subscription from service and move it to component.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class DataService {
private ROOT_URL = 'https://jsonplaceholder.typicode.com';
constructor(private http: HttpClient) {}
getPosts() {
return this.http.get(`${this.ROOT_URL}/posts`);
}
}
AppComponent.ts
import { Component } from '#angular/core';
import {DataService} from './data.service';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
constructor(public data:DataService){
this.data.getPosts().subscribe(data=>{
console.log(data);
})
}
}
See the Demo here
import { HttpClientModule } from '#angular/common/http';
//This is the service code:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class DataService {
private ROOT_URL = 'http://jsonplaceholder.typicode.com';
constructor(private http: HttpClient) {}
getPosts() {
//if you want to use the observable which returns from .get()
//.. you need to do "return"
return this.http.get(`${this.ROOT_URL}/posts`);
}
}
//app.component.ts:
import { Component, OnInit } from '#angular/core';
import { DataService } from '../../services/data.service';
#Component({
selector: 'app-root',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class AppComponent implements OnInit {
data;
constructor(private dataService: DataService) {
this.data = dataService.getPosts();
//so if you want to use the value of your http call outside..
//..of the service here is a good place where to do subscribe()
this.data.subscribe(data => {
console.log(this.data;
});
}
ngOnInit() {
}
}
You expect a return value and returns nothing. Your return statement is placed inside a nested-lambda function, thus using "return" in the place you used it causes the inner function to return a value, and not the outer one as you needed.
I suggest you to read about asynchronous programming, and particularly about Observable (which works on the same concept of Promise) in Angular.
I basically agree to #Eduardo Vargas answer, but it might be also a good idea to do it in resolver, which will call api, and put data into route snapshot. Thanks to this it won't wait on empty page for loading the data on subscribe in constructor. More info here:
https://blog.thoughtram.io/angular/2016/10/10/resolving-route-data-in-angular-2.html