Get JSON data from API with Angular 2 - json

I am trying to get some JSON data by API that I have created, but it does not receive it. I have used the following Angular code:
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //It does not show anything
return res.json();
})
However the getBooks() method has no problems getting the data. There are no errors in the browser console.
This is the whole service code:
import { Injectable } from '#angular/core';
import { Http } from "#angular/http";
import 'rxjs/add/operator/map';
import { Observable } from "rxjs/Observable";
#Injectable()
export class LibrosService {
url: string = "http://localhost/API/public/index.php/api/";
constructor(private _http: Http) { }
getBooks(){
return this._http.get(this.url + 'books')
.map(res => res.json()); //it works
}
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //it does not work
return res.json();
})
}
Sorry for my English if it is not very good and thank you for your help.

In Service
getHeroes(): Observable<Hero[]> {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
In Component
getHeroes() {
this.heroService.getHeroes()
.subscribe(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}

Fortunately, a friend helped me find the solution because the most frustrating thing was console did not show any errors. And the problem was not in service, it was in component.
Here is my solution:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from "#angular/router";
import { BooksService } from "app/services/books.service";
import { Subscription } from "rxjs/Subscription";
#Component({
selector: 'app-book',
templateUrl: './book.component.html'
})
export class BookComponent implements OnInit {
public book: any =[];
private sub: Subscription;
public errorMessage: string;
constructor( private _activatedRoute: ActivatedRoute,
private _booksService: BooksService ) {}
ngOnInit() {
this.sub = this._activatedRoute.params
.subscribe(params => {
let id = +params['id'];
this.getBok(id);
});
}
getBok(id){
this._booksService.getBook(id)
.subscribe(book => {
this.book = book,
error => this.errorMessage = <any>error
});
}
}
Thanks all of you for your help.

Related

Using Angular11, how does my HomeComponent retrieve the data provided by the Subject in DataService?

In order to make the data accessible through out the app, I created a new service called the DataService where I want to store my data coming from the API in a Subject.
While I do get the data, I cen see the array of objects in a log from DataService, my array in HomeComponent that should get the data is undefined in the console:
browser inspector console output
I imagine I have some stupid errors in my code, I am a beginer. Could you help me ?
HomeComponent:
import {Component, OnInit, Output} from '#angular/core';
import {DataService} from '../../shared/services/data.service';
import {Subscription} from 'rxjs';
import {Article} from '../../shared/models/article';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
#Output() articles?: Article[];
articleSubscription?: Subscription;
constructor(private dataService: DataService) { }
ngOnInit(): void {
this.dataService.emitArticlesSubject(this.dataService.loadArticles());
this.articleSubscription =
this.dataService.articlesSubject.subscribe(
(articles) => {
this.articles = articles;
}
);
console.log('HOME COMPONENT: ngOnInit: this.articles : ' + JSON.stringify(this.articles));
}
}
DataService:
import { Injectable } from '#angular/core';
import {BehaviorSubject, Subject} from 'rxjs';
import {ArticleService} from './article.service';
import {Article} from '../models/article';
#Injectable({
providedIn: 'root'
})
export class DataService {
articles?: Article[];
message = 'Aucun résultat ne correspond à votre recherche.';
articlesSubject = new Subject<Article[]>();
constructor(private articleService: ArticleService) { }
emitArticlesSubject(action: any): void {
this.articlesSubject.next(action);
}
/**
* Method to be served as a parameter
* to the 'emitArticlesSubject' method
* to load articles sorted by date.
*/
loadArticles(): any {
this.articleService.getAll().subscribe(
data => {
this.articles = data._embedded.articles;
console.log('DataService: loadArticles() : ' + JSON.stringify(this.articles));
},
error => {
console.log('ERROR: DataService not able to loadArticles !' );
}
);
}
/**
* Method to be served as a parameter
* to the 'emitArticlesSubject' method
* to load articles sorted by last activity.
*/
loadArticlesByActivity(): any {
this.articleService.getAllSortedByActivity().subscribe(
data => {
this.articles = data._embedded.articles;
},
error => {
console.log('ERROR: DataService not able to loadArticlesByActivity');
}
);
}
}
ArticleService:
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
import {Article} from '../models/article';
import {ResponseEntities} from '../../core/ResponseEntities';
const baseUrl = 'http://localhost:8080/articles';
const queryUrl = '?search=';
const dateUrl = '?sort=date,desc';
#Injectable({
providedIn: 'root'
})
export class ArticleService {
constructor(private http: HttpClient) { }
getAll(): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}${dateUrl}`);
}
getAllSortedByActivity(): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${dateUrl}`);
}
search(term: string): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${queryUrl}${term}`);
}
get(id: any): Observable<Article> {
return this.http.get<Article>(`${baseUrl}/${id}`);
}
create(data: any): Observable<any> {
return this.http.post(baseUrl, data);
}
update(id: any, data: any): Observable<any> {
return this.http.put(`${baseUrl}/${id}`, data);
}
delete(id: any): Observable<any> {
return this.http.delete(`${baseUrl}/${id}`);
}
deleteAll(): Observable<any> {
return this.http.delete(baseUrl);
}
findByTag(tag: any): Observable<Article[]> {
return this.http.get<Article[]>(`${baseUrl}?tag=${tag}`);
}
}
The problem could be related to subscription in data service.
this.dataService.emitArticlesSubject(this.dataService.loadArticles());
in this line emitArticlesSubject() called. but loadArticles() subscribed to underlaying service. emitArticlesSubject() only call loadArticles() and does not wait for its subscription to get complete. that causes articlss to be undefined. you should use promise in loadArticles() or change your service structures and call ArticleService directly in your HomeComponent.
In your HomeComponent you are console logging the contents of this.articles before the articles have actually been fetched. If you want to log the articles after they have been fetched, you can console log in the subscription instead:
this.articleSubscription =
this.dataService.articlesSubject.subscribe(
(articles) => {
this.articles = articles;
console.log('HOME COMPONENT: ngOnInit: this.articles : ' + JSON.stringify(this.articles));
}
);

How can I access the first element of JSON array data?

I'm using ionic as a front end and Laravel as a back end.
This is the returned JSON data from an API URL, I want to access just the first element which is a.jpg without anything else, I tried using filenames.[0] but it's just displaying [ which means that it's calling the first character not the first element of the array.
Here's the JSON data:
[{"filenames":"[\"a.jpg\",\"b.jpg\",\"c.jpg\"]"}]
Here's my .ts file
import { ApiLandingRecipesService} from '../api-landing-recipes.service'
#Component({
selector: 'app-landing-page',
templateUrl: './landing-page.page.html',
styleUrls: ['./landing-page.page.scss'],
})
export class LandingPagePage implements OnInit {
datauser: any[];
constructor( public api: ApiLandingRecipesService) { }
ngOnInit() {
this.getDataUser();
}
async getDataUser() {
await this.api.getDataUser()
.subscribe(res => {
console.log(res);
this.datauser =res;
console.log(this.datauser);
}, err => {
console.log(err);
});
}
and Here's my service file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
const apiUrl = "https://example.com/showimages";
#Injectable({
providedIn: 'root'
})
export class ApiLandingRecipesService {
constructor(private http: HttpClient) { }
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError('Something bad happened; please try again later.');
}
private extractData(res: Response) {
let body = res;
return body || [] ; }
getDataUser(): Observable<any> {
return this.http.get(apiUrl, httpOptions).pipe(
map(this.extractData),
catchError(this.handleError));
}
}
It's because filenames is indeed a string (a json string representation of the array) and not an array.
Try converting the string into an array first.
JSON.parse(filenames)[0]
The value of filenames here is a string and not an array, which is why you're getting [ when you try to access the first element.
You probably need to parse the value, here's an example (assuming datauser) is the JSON data you've shown us.
let filename = JSON.parse(datauser[0].filenames)[0]

Angular6 error: the data which I am getting from api is in the string format,below is the response image

hi want to show the data from my api to my frontend (Angular 6), but this error comes up: I am using HttpClient method from angular 6 I am new to angular
Angular6 error: the data which I am getting from api is in the string format, I need to convert it to object, below is the response image
this is model.ts
export class Incident {
public Title: string;
public status: string;
constructor(Title: string, status: string) {
this.status = status;
this.Title= Title;
}
}
this is component
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Incident } from '../../shared/incidents.model';
import { DataStorageService } from '../../shared/data-storage.service';
#Component({
selector: 'app-active-incident',
templateUrl: './active-incident.component.html',
styleUrls: ['./active-incident.component.css']
})
export class ActiveIncidentComponent implements OnInit {
incidents: Incident[];
constructor(private router: Router, private dataStorageService: DataStorageService) { }
ngOnInit() {
this.dataStorageService.getIncidents()
.subscribe(
(data: Incident[]) => this.incidents = data,
(err: any) => console.log(err),
() => console.log('All done getting incidents')
);
}
this is service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Incident } from './incidents.model';
#Injectable()
export class DataStorageService {
constructor(private http: HttpClient) {}
getIncidents(): Observable<Incident[]> {
console.log('Getting all incidents from server');
return this.http.get<Incident[]>
('api/url');
}
}
my json
{
"Events": ["{'title': 'some title', 'Incident_Status': 'status'}",
"{'title': 'some title', 'Incident_Status': 'status'}"]
}
html view
<div class="card" *ngFor="let incident of incidents">
<div class="card-header">
<span class="badge badge-danger"></span>{{incident.Title}}
<span class="badge badge-danger"></span>{{incident.Incident_Status}}
</div>
</div>
You are trying to iterate an object instead of an array. This happens because the list of events are inside the Events key, but you aren't accessing it to extract the list of events. Instead you are using the root of the response object.
Corrected code:
ngOnInit() {
this.dataStorageService.getIncidents()
.subscribe(
(data: Incident[]) => this.incidents = data.Events, // <--
(err: any) => console.log(err),
() => console.log('All done getting incidents')
);
}

How to parse an array of json object to typescript (object) after a get method

I am a beginner in angular and start to build my first app.My goal is to build a generic service that will be inherited from others service. I am following the structure of this link to my approach Generic HTTP Service .In read method i`m using Serializer class to convert the response json object to my typescript an it work. I got a map error. How can I solve it?
Service code:
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Resource } from '../models/resource.model';
import { Observable } from 'rxjs/Observable';
import { Serializer } from '../serializer/serializer';
import { AuthenticationService } from './authentication.service';
#Injectable()
export class SharedService<T extends Resource> {
constructor(
private httpClient: HttpClient,
private url: string,
private endpoint: string,
private authentication: AuthenticationService,
private serializer: Serializer
) { }
create(resource: T) {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8');
return this.httpClient.post(`${this.url}/${this.endpoint}`, JSON.stringify(resource), { headers: headers });
}
//PUT
update(item: T): Observable<T> {
return this.httpClient.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), { headers: this.addHeaders() })
.map(data => this.serializer.fromJson(data) as T);
}
//GET
read(id: number): Observable<T> {
return this.httpClient.get(`${this.url}/${this.endpoint}/${id}`, { headers: this.addHeaders() })
.map((data: any) => this.serializer.fromJson(data) as T);
}
//GET ALL
list(): Observable<T[]> {
return this.httpClient.get<T>(`${this.url}/${this.endpoint}` , {headers : this.addHeaders()})
.map((data: any) =>
this.convertData(data.items));
}
protected convertData(data: any): T[] {
return data.map(item => {this.serializer.fromJson(item)});
}
protected addHeaders() {
let token = ('Bearer ' + this.authentication.getToken()).valueOf();
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8').set('Authorization', token);
return headers;
}
}
UserService:
import { Injectable } from '#angular/core';
import { SharedService } from './shared.service';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { User } from '../models/user/user.model';
import { AuthenticationService } from 'app/service/authentication.service';
import { UserSerializer } from '../serializer/user-serializer';
import { NgForm } from '#angular/forms';
#Injectable()
export class UserService extends SharedService<User>{
constructor(httpClient: HttpClient, authenticate: AuthenticationService) {
super(httpClient,
'http://localhost:8084/SuperCloud/webresources',
'user',
authenticate,
new UserSerializer()
);
}
UserSerializer:
import { User } from "../models/user/user.model";
import { Serializer } from "./serializer";
import { Resource } from "../models/resource.model";
export class UserSerializer extends Serializer {
fromJson(json: any): Resource {
const user = new User();
user.id = json.id;
user.name = json.name;
user.surname = json.surname;
user.email = json.email;
user.phoneNumber = json.phoneNumber;
user.password = json.password;
user.username = json.username;
user.active = json.active;
console.log('serializer');
console.log(user);
return user;
}
}
User model:
import { Resource } from "../resource.model";
export class User extends Resource{
username: string;
email: string;
name: string;
surname: string;
phoneNumber: string;
password?: string;
active : boolean;
}
UserService inherited inherited:
ngOnInit() {
this.userService.list().subscribe(
(data) => console.log(data)
);
}
Error:
core.es5.js:1020 ERROR TypeError: Cannot read property 'map' of
undefined
at UserService.SharedService.convertData (shared.service.ts:53)
at MapSubscriber.eval [as project] (shared.service.ts:48)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:95)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)
First of all, I assume the data that you passed into convertData function is not an array.
Only Array or Observable have map function in this case.
Also, chained function has been changed into pipeable operators in RxJS 6
https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Secondly, looking at the error message - I don't think the data value returned from the endpoint has value.
Third, data.map(item => {this.serializer.fromJson(item)}); - if the arrow function inside the map function is wrapped in curly bracket, you need to have return keyword.
in other word, data.map(item => {this.serializer.fromJson(item)}); should be data.map(item => this.serializer.fromJson(item)); or data.map(item => {return this.serializer.fromJson(item)});
Use subscribe instead of map to return the response.
return this.httpClient
.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), {
headers: this.addHeaders()
})
.subscribe(data => this.serializer.fromJson(data) as T);
BTW RXJs6 has changed the implementation of using observable map function

I get a error while publishing a app. The error is property json does not exist on type object

when I try to test the app in Ionic serve command, I didn't get any error. But when i try to publish the app, I get the error as "property json does not exist on type object" . The error takes place during the transpile stage:
How to solve this problem? I tried with every possibility, but i didn't get my problem solved.
Home.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { WeatherProvider } from '../../providers/weather/weather';
import { Storage } from '#ionic/storage';
//import { Response } from '#angular/http';
//import 'rxjs/add/operator/map';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
weather:any;
location:{
city:string,
state:string
}
constructor(
public navCtrl: NavController,
private weatherProvider:WeatherProvider,
private storage: Storage) {
}
ionViewWillEnter(){
this.storage.get('location').then((val)=>{
if(val!=null){
this.location = JSON.parse(val);
}else{
this.location = {
city: 'Chennai',
state: 'TN'
}
}
this.weatherProvider.getWeather(this.location.city,this.location.state)
// .map((res: Response) => res.json() )
.subscribe(weather => {
this.weather = weather.current_observation;
});
});
}
}
Weather.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
//import { Response } from '#angular/http';
//import 'rxjs/add/operator/map';
//import 'rxjs/Rx';
#Injectable()
export class WeatherProvider {
apiKey = '6d3243fb22b01d0c';
url;
constructor(public http: HttpClient) {
console.log('Hello WeatherProvider Provider');
this.url = 'http://api.wunderground.com/api/'+this.apiKey+'/conditions/q';
}
getWeather(city, state){
return this.http.get(this.url+'/'+state+'/'+city+'.json')
// .map(res => res.json());
// .map((res: Response) => res.json() );
}
}
Typescript is all about typing. So you should state the type of object you'are receiving from the method getWeather. Start by creating a class Weather at the end of home.ts (look below)
class Weather {
current_observation: string;
}
and make this change:
this.weatherProvider.getWeather(this.location.city,this.location.state)
// .map((res: Response) => res.json() )
.subscribe((weather: Weather) => {
this.weather = weather.current_observation;
});
});
}
ionViewWillEnter(){
this.storage.get('location').then((val) => {
if(val != null){
this.location = JSON.parse(val);
} else{
this.location ={
city: 'miami',
state: 'FL'
}
}
//Try below code
this.weatherprovider.getweather(this.location.city, this.location.state).subscribe(result => {
let weather:any = result;
this.weather = weather.current_observation;
console.log(this.weather);
});
});
}