This question already has an answer here:
Angular: Typescript casting JSON response as object model not working
(1 answer)
Closed 5 years ago.
I have a java webservice that out puts a list of Json objects with this properties >
public class Oferta {
private int id;
private String categoria;
private String descricao_oferta;
private String anunciante;
private double valor;
private boolean destaque;
private List<String> imagens;
}
And i have a Angular4 project that i want to retrieve this json and store in a Array. How should i do this?
Angular4 oferta model:
export class Oferta {
public id: number;
public categoria: string;
public titulo: string;
public descricao_oferta: string;
public anunciante: string;
public valor: number;
public destaque: boolean;
public imagens: Array<Object>;
}
Method that i can retrieve the list of json objects(works fine, when i console.log(getData) i recieve the list of json objects. :
public getData(): Promise<Oferta[]>{
this.ofertas = this.http.get(this.apiURL)
.map((res: Response) => <Oferta[]>res.json()) << ERROR WHEN CASTING
return new Promise((resolve,reject)=>{
let deu_certo = true
if(deu_certo){
setTimeout(() => resolve(this.ofertas),3000);
}
else{
reject({codigo_erro: 404,mensagem_erro: 'Servidor nao encontrado'})
}
//console.log('passou aqui')
})
.then(( ofertas: Oferta[]) => {
console.log('segundo then')
return new Promise((resolve2,reject2) => {
setTimeout(() => {resolve2(ofertas )},3000)
})
})
.then((ofertas: Oferta[]) => {
console.log('terceiro then executado apos 3 sec , aguardando outra promisse ser resolvida')
return ofertas;
})
}
Now how can i convert this to a Array? Already tried this.oferta[] = res.json(); Wont let me.
///////////// This is how i call at home.component
ngOnInit() {
this.ofertas = this.ofertasService.getData()
this.ofertasService.getOfertas2()
.then(
( ofertas: Oferta[] ) => { this.ofertas = ofertas
console.log('a funçao resolve() foi resolvida depois de 3 segundos')
})
.catch((param: any) => {
console.log(param)
})
}
You simply have to typecast the data provided your class property names match the json properties.
getData():Promise<Oferta[]>{
return this.http.get(this.apiURL)
.map((res: Response) => <Oferta []>res.json()).toPromise()
}
You will have to import the toPromise function from rxjs
Update: i was able to do it using this:
this.http.get(this.actionUrl)
.map(res => res.json())
.subscribe(
data => {
this.ofertas = data;
},
err =>
console.log('cant get ofertas'),
() => console.log('FOi')
But only directly on my Home.component.ts, tried doing it with a method getData from my Oferta.service.ts, i cant use http in oferta.service, so not sure how im going to do this in a differente class apart from the component.
Related
My model looks like this:
export interface IFlightPlan {
flightPlanId: string;
aircraftIdentification: string;
aircraftType: string;
airspeed: number;
altitude: number;
flightType: string;
fuelHours: number;
fuelMinutes: number;
departureTime: Date;
arrivalTime: Date;
departureAirport: string;
arrivalAirport: string;
route: string;
remarks: string;
numberOnBoard: string;
}
And a sample of the JSON response from my API looks like this. The API returns an array of 25 of these:
{
"flight_plan_id":"f1d193ad0153491f9cf61cbe39c7db70",
"aircraft_identification":"N67SVS",
"aircraft_type":"PA-34 Piper Seneca",
"airspeed":128,
"altitude":12000,
"flight_type":"VFR",
"fuel_hours":3,
"fuel_minutes":41,
"departure_time":"2022-07-08T00:26:45Z",
"estimated_arrival_time":"2022-07-08T03:49:45Z",
"departing_airport":"KBXA",
"arrival_airport":"KNZY",
"route":"KBXA JOH J46 DMDUP J46 KNZY",
"remarks":"",
"number_onboard":4
}
As you can see, the properties of my model and those of the JSON response differ in casing and spelling.
Here's my Angular response service:
#Injectable({
providedIn: 'root'
})
export class FlightplansService {
private apiUrl = "https://localhost:3001/api/v1/flightplan";
constructor(private http: HttpClient) { }
getFlightPlans(): Observable<IFlightPlan[]> {
return this.http.get<IFlightPlan[]>(this.apiUrl).pipe(
tap(data => console.log('ALL FLIGHT PLANS: ', JSON.stringify(data))),
catchError(this.handleError)
);
}
handleError(err: HttpErrorResponse) {
let errorMessage = '';
errorMessage = `An error has occurred: ${err.error.message}`;
console.log(errorMessage);
return throwError(() => errorMessage);
}
}
and here's where I'm using it in my component
ngOnInit(): void {
this.flightPlanService.getFlightPlans().subscribe({
next: (data => this.flightPlans = data),
error: (err => this.errorMessage = err)
})
I can't access any of this.flightPlans[] children's properties. I don't quite understand what's going on by my guess is that this.flightPlans[] is assigned a generic array instead of IFlightPlan[] array because there's no way to map from the JSON to the model
How do I fix this?
Use map inside the pipe and define a result object as IFlightPlan as flowing:
getFlightPlans(): Observable<IFlightPlan[]> {
return this.http.get<IFlightPlan[]>(this.apiUrl).pipe(
map(flightPlans => flightPlans.map(item =>
{
let flightPlan: IFlightPlan = {
flightPlanId: item.flight_plan_id,
aircraftIdentification: item.aircraft_identification,
...
}
return flightPlan;
}
)),
tap(data => console.log('ALL FLIGHT PLANS: ', JSON.stringify(data))),
catchError(this.handleError)
);
}
UPDATE:
While you'll map the incoming data after reading so it's enough to make http.get read the data as array of any as flowing:
getFlightPlans(): Observable<any[]> {
return this.http.get<any[]>(this.apiUrl).pipe(
map((flightPlans) =>
flightPlans.map((item) => {
let flightPlan: IFlightPlan = {
flightPlanId: item.flight_plan_id,
aircraftIdentification: item.aircraft_identification,
..
};
return flightPlan;
})
),
tap((data) => console.log('ALL FLIGHT PLANS: ', JSON.stringify(data))),
catchError(this.handleError)
);
}
Don't forget to fill the right fields names from item
Im trying to get data from a json file that equal the name of the player in the url. For example: localhost:4200/players/Febiven should only return the information about Febiven. Im using Angular 6
So far I have this code:
player.service.ts
get(ingameName){
return <Observable<Player>> this.http.get(endpoint).map(response =>{
let data = response.filter(item=>{
if (item.ingameName == ingameName) {
return item
}
});
if (data.length == 1){
return data[0]
}
return {}
})
.catch(this.handleError)
}
private handleError(error:any, caught:any): any{
console.log(error, caught)
}
player-info.component.ts
export interface Player {
ingameName: string;
name: string;
intro: string;
image: string;
info: string;
team: string;
dob: string;
earnings: string;
role: string;
game: string;
favourite: string;
IDs: string;
}
export class PlayerInfoComponent implements OnInit {
players: Player[] = null;
private routeSub:any;
private req:any;
ingameName:string;
player : player;
constructor(private route: ActivatedRoute, private plService : PlayerService) { }
ngOnInit() {
this.routeSub = this.route.params.subscribe(params => {
this.ingameName = params['ingameName'];
this.req = this.plService.get(this.ingameName).subscribe(data=>{
this.player = data as player
})
});
Im getting the error 'Property 'filter' does not exist on type 'Object'. And I don't really have an idea how to fix this, I looked at multiple answers, but none seemed to work for me. If someone could help me with fixing this error thatd be great
Thanks
filter only exists on arrays. Your response is an object. You can do this instead:
get(ingameName){
return <Observable<Player>> this.http.get(endpoint).map(response =>{
let data = response.json();
if (data.ingameName == ingameName){
return data;
}
return {};
})
.catch(this.handleError)
}
Try this it will work:
define a parameter inside your class & use it in ngOnInit() function like this:
export class VideoDetailComponent implements OnInit, OnDestroy {
data_new:any;
ngOnInit() {
this.http.get("assets/json/videos.json").subscribe(data =>{
this.data_new = data;
this.data_new.filter(item=>{
console.log(item)
// do your work here
})
})
}
}
I am trying to get a data from json file in the assets folder, and then assign this data to a variable that will be binded to another #Input variable of a child componenet.
Code
Based on multiple solutions on the net, I retrieve my JSON data this way:
#Injectable()
export class JSONService {
constructor(private http: HttpClient) { }
public fromJSON(jsonFileName: string): Observable<any[]> {
let result: any[] = new Array();
let pathToJson: string = "assets/" + jsonFileName + ".json";
return this.http.get(pathToJson).map(data => {
let result: any[] = new Array();
// Apply some treatment on data and push it to the result array
return result;
});
}
}
I then call my service in the ngOnInit() method of the parent component:
ngOnInit() {
this.jsonService.fromJSON("users.json").subscribe(fields => {
this.fields= fields;
console.log(this.fields); // Log (I): this.fields is well defined
});
console.log(this.fields); // Log (II): this.fields is undefined
}
Where the variable fields is binded to a child component:
<child-component [childFields] = "fields"></child-component>
Problem
The problem that I am facing is that the asynchronous call to the fromJSON method causes this.fields to be undefined at some point of the lifecycle of the page execution (Log (II) from the code above), and this causes to send an undefined value of the this.fields variable to the child component.
How to avoid to have an undefined value of the fields variable, and make sure that the child component is always loaded with the data from the json file?
Just add *ngIf to check if the data is loaded
<child-component *ngIf="fields" [childFields] = "fields"></child-component>
Service.ts
#Injectable()
export class JSONService {
constructor(private http: HttpClient) { }
public fromJSON(jsonFileName): Observable<any[]> {
console.warn('Retriving Default Data from File.......');
return this.http.get(filename)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || [];
}
private handleError(error: any) {
const errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
console.log('Server Error!');
return Observable.throw(errMsg);
}
}
parent.component.ts
constructor(public jsonService: jsonService) {
}
ngOnInit() {
this.jsonService.fromJSON('assets/users.json').subscribe(
function (success) {
this.data = success;
this.datahandle(success);
},
error => console.log('Getting Server Data Error :: ' +
JSON.stringify(error)));
}
datahandle(jsonData){
console.log('check data' + JSON.stringify(jsonData)); <-----check data
// may parse your jsonData if required
this.fields = jsonData ;
let keys = Object.keys(jsonData);
console.log(keys);
}
}
parent.component.html
<child-component *ngIf="fields" [childFields] = "fields"></child-component>
Assuming your component is somewhat like below
export class SomeComponent implements OnInit {
public fields: any[];
ngOnInit() {
this.jsonService.fromJSON("users.json").subscribe(fields => {
this.fields = fields;
console.log(this.fields); // Log (I): this.fields is well defined
});
console.log(this.fields); // Log (II): this.fields is undefined
}
}
Then you can either initialize fields with an empty array
public fields: any[] = [];
OR in template
<child-component *ngIf="fields" [childFields]="fields"></child-component>
I have a file location.json, containing JSON string of the form:
{
"locations": [
{
"id": 1,
"places": [
{
"id": 1,
"city": "A",
"state": "AB"
}
]
}
}
I created classes of the form:
export class Location{
constructor(public id: number,
public places: Place[],
}
export class Place {
constructor(
public id: number,
public city: string,
public state: string
}
How do I parse the JSON string to object? I did something like this:
...
export class DashboardComponent {
locations: Locations[];
constructor(private locationService:LocationService) {
this.getLocations()
}
getLocations(){
this.locationService.get('assets/location.json')
.subscribe(res => this.location = res);
}
Depending on what's the result for the subsriber it can be:
.map(res => this.location = res.json().locations);
Or:
.subscribe(res => this.location = JSON.parse(res).locations);
But keep in mind that that won't instiantiate instances for your classes, it will only assign the values as regular js object which match the following:
interface Location {
id: number;
places: Place[];
}
interface Place {
id: number;
city: string;
state: string;
}
If you want instances of the classes you'll need to do something like:
JSON.parse(res)
.locations.map(location => new Location(location.id,
location.places.map(place => new Place(place.id, place.city, place.state)))
usually you map response with res => res.json() somewhere in the service method but json should have a valid format, otherwise it won't parse.
Note, that response is an Object and you can't parse it but only body of the response.
return this.http.get(url,options).map((response) => this.parseResponse(response))
.catch((err) => this.handleError(err));
private handleError(error: any) {
let body = error.json();
return Observable.throw(body);
}
private parseResponse(response: Response) {
return response.json();
}
I have the following code (based on the Angular2 Hero example) and I am trying to get a JSON API call (AWS) converted into a TypeScript class.
The code returns no errors, and I can see that the object is there when I look at response.json() but the class product remains undefined, any ideas?
Code in the service file...
getProduct(id: number): Promise<Product> {
const url = `${this.ProductsUrl}/${id}`;
console.log(url);
return this.http.get(url)
.toPromise()
.then(response => response.json().data as Product)
.catch(this.handleError);
}
Code in the component file...
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => this.productsService.getProduct(+params['id']))
.subscribe(product => this.product = product);
}
The class...
export class Product {
Instock: boolean;
Description: string;
CategoryId: number;
Id: number;
ColourOptions: string[];
Name: string;
}
The JSON returned from the API call...
{
"Instock":true,
"Description":"This is a test description.",
"CategoryId":1,"
Id":1,
"ColourOptions":["Red","Gold","Green"],
"Name":"Test"
}
switchMap'callback must return an Observable not a Promise, so edit getProduct to return a Observable instead:
getProduct(id: number): Observable<Product> {
const url = `${this.ProductsUrl}/${id}`;
console.log(url);
return this.http.get(url)
.map(response => response.json().data as Product)
.catch(this.handleError);
}