Angular calling API with observable is not displaying data - json

I have implemented an angular 5 application to bring data from a Web API. I am using an observable to get the json. The Json coming from the API looks like this:
{
"Job": [
{
"Title": "Solution Architect",
"Summary": "Solution Architect",
"Salary": {
"MinValue": "100",
"MaxValue": "100",
"Text": "",
"Period": "HourlyRate"
},
"Reference": "234483_1",
},
{
"Title": "Senior Business Analyst – eCommerce ",
"Summary": "Senior Business Analyst...",
"Salary": {
"MinValue": "80",
"MaxValue": "100",
"Text": "",
"Period": "HourlyRate"
},
"Reference": "234874_1",
}
],
"Advertiser": "Resourcing",
"Source": "Wiz"
}
I have created a service looks as follows:
....
#Injectable()
export class AdvDataService {
private _getAddsUrl = 'https://xx.xxxx.com/v1/adverts/www111';
constructor(private _http: Http) { }
getAdvForClient(): Observable<IAdv> {
return this._http.get(this._getAddsUrl)
.map((response: Response) => <IAdv>response.json())
.do(data => console.log('All:' + data))
.catch(this.handleError);
}
The component looks like that:
....
export class HomeComponent implements OnInit {
constructor(private _sdvDataService: AdvDataService) { }
private loadAdverts: IAdv;
private errorMesage: string;
ngOnInit() {
this.errorMesage = "";
this._sdvDataService.getAdvForClient()
.subscribe(adv => {
this.loadAdverts = adv;
console.log ("here:" + this.loadAdverts)
}, error => {
this.errorMesage = <any>error;
});
}
}
I have a simple interface:
export interface IAdv {
Advertiser: string,
Source:string
}
and my html:
<div *ngIf="loadAdverts" >
<div class="row justify-content-center">
<div class="card" style="width: 20rem;">
<div class="card-body">
<h4 class="card-title">here: {{loadAdverts.Advertiser}}</h4>
<h6 class="card-subtitle mb-2 text-muted">{{loadAdverts.source}} </h6>
<p class="card-text">{{loadAdverts.source}}</p>
Card link
Another link
</div>
</div>
</div>
I can see the json displayed in the console from both console.log in the component and in the service but any data is displayed in the view.
I would appreciate any help?
Update: It seems the json coming from the server is a json string. So it is not being parsed in the observable. I had to use json.parse in the suscriber. How can I parse that json string to a json object automatically with the suscriber?

Your loadAdverts is a private variable and thus not accessible in the template.
Either make it public like this.
public loadAdverts:IAdv;
or use getters and setters.
private _loadAdverts:IAdv;
....
get loadAdverts(): IAdv {
return this._loadAdverts;
}
set loadAdverts(_ad: IAdv) {
this._loadAdverts = _ad;
}
....

As we can see, you are receiving an Object Job containing an array, so you should extract that array from the object:
getAdvForClient(): Observable<IAdv> {
return this._http.get(this._getAddsUrl)
.map((response: Response) => <IAdv>response.json().Job) // here!
.do(data => console.log('All:' + data))
.catch(this.handleError);
}
also, since you are getting an array, you would want to iterate that in your template:
<div *ngFor="let adv of loadAdverts">
<p>{{adv.Source}}</p>
<!-- more code here -->
</div>
also notice that this is case sensitive, in your template you used source as the property name instead of Source.

Related

How to read nested JSON Objects in a service call in Angular 6

I have a nested JSON object at an API end point like below
[
{
"id": "order-1",
"recipient": {
"name": "John Smith",
"email": "j.smith#notgmail.com"
},
"created_at": "2018-11-01T09:42:30Z",
"items": [
{
"id": "item-1",
"name": "Supersoaker 3000",
"quantity": 2,
"total_price": {
"currency": "EUR",
"amount": "24.33"
}
},
{
"id": "item-2",
"name": "Nunchucks XXX",
"quantity": 1,
"total_price": {
"currency": "EUR",
"amount": "39.99"
}
}
],
"delivery": {
"courier": "DPP",
"method": "Express"
},
"charge_customer": {
"currency": "EUR",
"total_price": "18.00"
}
}
]
I am trying to call a service in order-results-service.ts to GET the nested objects from the api like below:
getOrderResult(): Observable <IOrder[]>{
this.getSubmitCriteria();
return this.http.get<serverData>(this.url, this.submitCriteria)
.pipe(map(res => <IOrder[]>res.orders),
catchError(this.handleError('getOrderResult',[])));
}
I am defining an IOrder[] interface like below in interface.ts:
interface Recepient {
name?: string;
email?: string;
}
interface Delivery {
courier?: string;
method?: string;
}
interface totalPrice {
currency?: string;
total_price?: number;
}
interface Items {
id?: string;
name?: string;
}
export interface IOrder {
recepient: Recepient[];
totalPrice: totalPrice[];
createdDate: string;
items: Items[];
deliveryDetails: Delivery[];
}
And in the order.component.ts I am calling the service like below:
ngOnInit() {
this.loadData();
}
loadData(){
this.orderResultsService.getOrderResult().subscribe((data: IOrder[]) => {
this.orders = data;
}), error => {
this.errormsgs = [{ severity: 'error', detail: 'error'}];
}
}
But I am unable to get the values from the JSON object in the component when i subscribe to the observable. I am getting the values in the service. I also need help on how to display the data objects in the front end. I tried using from PrimeNG and also used *ngFor like below in html:
<div *ngFor="let order of orders">
<div *ngFor="let x of order.recipient">
<strong>Recipient Name:</strong>{{x.name}}
<strong>Recipient Email Address:</strong>{{x.email}}
</div>
<div *ngFor="let y of order.items">
<strong>Item Id:</strong>{{y.id}}
<strong>Item Name:</strong>{{y.name}}
</div>
<div>
<strong>Time when order was made:</strong>{{order.created_at}}
</div>
<div *ngFor="let z of order.delivery">
<strong>Courier Name:</strong>{{z.courier}}
<strong>Courier Method:</strong>{{z.method}}
</div>
<div *ngFor="let p of order.charge_customer; let i =index">
<strong>Total Price of the Order:</strong>{{p.amount}}{{p.currency}}
</div>
</div>
But I am unable to get the values in the front end or in the service. What am I doing wrong here?
Use this to extract values. Example -
data["recipient"].name and data["recipient"].email and put this in a variable. Like this example only try to extract data.

How to read in Angular 2 the JSON #text

Sorry, but I'm stagnant to read a very specific JSON value in Angular 2&4, where I can obtain and showing the name of the list BUT! but I can't find a way to show in the page, what I'm talking about for example in the JSON document I have this way: (obtained from http://www.last.fm/api/show/artist.getTopAlbums ) and I'm using the Postman to check all the contents, I can obtain the name of the Album and other things, BUT to obtain the #text to use the image it's weird
"topalbums": {
"album": [
{
"name": "The Very Best of Cher",
"playcount": 1663904,
"mbid": "a7e2dad7-e733-4bee-9db1-b31e3183eaf5",
"url": "https://www.last.fm/music/Cher/The+Very+Best+of+Cher",
"artist": {
"name": "Cher",
"mbid": "bfcc6d75-a6a5-4bc6-8282-47aec8531818",
"url": "https://www.last.fm/music/Cher"
},
**// +++++++++++++++++++THIS PART +++++++++++++++++++++!!!!!**
"image": [
{
// I'M TRYING TO USE THIS INFORMATION
"#text": "https://lastfm-img2.akamaized.net/i/u/34s/287bc1657795451399d8fadf64555e91.png",
"size": "small"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/64s/287bc1657795451399d8fadf64555e91.png",
"size": "medium"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/174s/287bc1657795451399d8fadf64555e91.png",
"size": "large"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/300x300/287bc1657795451399d8fadf64555e91.png",
"size": "extralarge"
}
]
},
What I want it's to obtain the "url" of the image, I try to obtain in this way:
artist.component.html
<div *ngFor="let list of albumes">
{{list.name}}
<hr>
<!-- Can't obtain the URL... -->
<img src="{{list.image[1].text}}" alt="">
</div>
artist.component.ts
import { Component, OnInit } from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import {MusicService} from "../../services/music.service";
#Component({
selector: 'app-artist',
templateUrl: './artist.component.html',
providers: [MusicService]
})
export class ArtistComponent implements OnInit {
constructor(private service: MusicService, private route: ActivatedRoute) { }
albumes: any[];
songs: any[];
ngOnInit() {
this.route.params.map(params => params['mbid']).subscribe(
mbid => {
// Top Album
this.service.GetTopAlbumArtist(mbid).subscribe(topalbum => {
this.albumes = topalbum.topalbums.album;
console.log(topalbum.topalbums.image);
});
// Top Tracks
// this.service.GetTopTracksArtist(mbid).subscribe(toptracks => {
// this.songs = toptracks;
// });
}
)
}
}
First, if you want to get the first position of image array, you should access the position 0 (not 1)... also you don't have text but #text:
To solve your problem you can do this way:
src="{{list.image[0]['#text']}}"
or even better:
[src]="list.image[0]['#text']"

parsing JSON into a Angular 2 object

I am having the following issue.
I have a very large JSON string that has all the variables from the object.
object:
export class User {
ssn:string;
userId:string;
firstName:string;
lastName:string;
middleName:string;
office:string;
role:string;
lockCode:string;
command:string;
street:string;
city:string;
position:string;
zip:string;
phone:string;
dsn:string;
fax:string;
email:string;
pwEffectiveDate:any;
pwVaildationDate:any;
fromDate:any;
toDate:any;
systemAccess:string;
dmType:string;
accessInfoEffectiveDate:any;
accessInfoEffectiveTo:any;
availableOffices: string[];
availbleRole:string[];
}
JSON :
#Injectable()
export class SearchService {
getData() :any[] { return [
{"snn": "26999935-7", "userId": "EVD404", "firstName": "Chaney", "lastName": "Vernon", "middleName": "X", "office": "ADURT", "role": "GC", "lockCode": "Q", "command": "5th Grp", "street": "953-1348 Faucibus Rd.", "city": "Bienne-lez-Happart", "position": "Developer", "zip": "76222", "phone": "233-969-1834", "dsn": "359-887-4719", "fax": "157-376-6377", "email": "mauris.rhoncus#rhoncusDonec.com", "pwEffectiveDate": "13/03/17", "pwVaildationDate": "27/01/18", "fromDate": "10/11/17", "toDate": "21/12/17", "systemAccess": "GC", "dmType": "XJ", "accessInfoEffectiveDate": "26/12/2016", "accessInfoEffectiveTo": "06/06/2016", "availableOffices": "UUU", "availbleRole": "GC"},
{"snn": "43250813-7", "userId": "NSB626", "firstName": "Addison", "lastName": "Vernon", "middleName": "X", "office": "AUTRO", "role": "GC", "lockCode": "O", "command": "11th ACR", "street": "Ap #904-5416 Semper, Road", "city": "s Herenelderen", "position": "Developer", "zip": "26457", "phone": "890-600-3144", "dsn": "679-122-1054", "fax": "913-500-7495", "email": "Aenean#molestiesodales.com", "pwEffectiveDate": "11/06/17", "pwVaildationDate": "01/03/17", "fromDate": "05/08/17", "toDate": "29/09/16", "systemAccess": "LIMIT", "dmType": "NB", "accessInfoEffectiveDate": "19/04/2017", "accessInfoEffectiveTo": "13/04/2016", "availableOffices": "LLL", "availbleRole": "USER"},
Then I want to be able to call methods like below when I pass my service into the component:
getUserByLastName(lastName):User[]{
let temp: User[]=[];
for(let d of this.data) {
if(d.lastName == lastName){
temp.push(d);
}
}
return temp;
}
I have tried to JSON.parse but that did not work. I tried a few other things but none seem to stick.
---------------------------------Update 1----------------------------
It has been brought to my attention that I should be using an Observable. Here is what I have in trying to implement that but it is currently not working:
getUserBySSN():Observable<User[]> {
return this._http.get(this._url)
.map((response: Response) => response.json())
.do(data => console.log("User data" + JSON.stringify(data)))
.catch(this.handleError);
}
private handleError(error: Response) {
console.log(error);
return Observable.throw(error.json().error || 'Internal Server error');
}
I created a json file and set the variable url as its path. However I am getting to following error:
The type argument for type parameter 'T' cannot be inferred from the
usage. Consider specifying the type arguments explicitly. Type
argument candidate 'Response' is not a valid type argument because it
is not a supertype of candidate 'Response'. Types of property 'type'
are incompatible. Type 'string' is not assignable to type 'ResponseType'
It was suggested I use .map((response: Response) => <User[]> response.json()) but I was not allow to convert it.
After further research I found this is the the best approach and am trying to get it to function so later on I can use it to do actual HTTP calls against the DB.
In the world of Angular2, you should be using rxjs to achieve your requirement, as shown below
Your component should subscribe to the service values as below
this.userService.getUsers()
.filter(users =>{
for(let user of users) {
if(user.lastName == 'Vernon'){
this.users.push(user);
}}})
.subscribe(users => this.users = users,
error =>this.errorMessage =<any> error);
Your service should raise http calls and return data as below
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import {User} from './user.model.ts';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
#Injectable()
export class UserService {
private _url = "src/data.json";
constructor(private _http: Http) {
}
getUsers(): Observable<User[]> {
return this._http.get(this._url)
.map((response: Response) => <User[]>response.json())
.do(data => console.log("User data" + JSON.stringify(data)))
.catch(this.handleError);
}
private handleError(error: Response) {
console.log(error);
return Observable.throw(error.json().error || 'Internal Server error');
}
}
Also, you should not use Class for holding your data model, instead use interface as shown in the demo below.
LIVE DEMO

map json response into nested typescript object with rxjs

In my Angular2-App I´m receiving a JSON-Response via http-Request that kind of looks like that:
{
"documents": [
{
"title": "Example-Doc 1",
"versions": [
{
"fileSize": 15360
},
{
"fileSize": 2048
}
]
},
{
"title": "Example-Doc 2",
"versions": [
{
"fileSize": 15360
},
{
"fileSize": 2048
}
]
}
],
"meta": {
"total": [2]
}
}
Now i wonder how to map this structure into my TypeScript-Classes, i checked different approaches, but it never worked. I actually need the constructor of the Version class to be called.
export class Document {
title: string; // Titel des Dokuments
versions: Version[];
}
If you have complex classes that need to be serialized and deserialized, I suggest that you implement static methods to your classes like fromJson and toJson - however without knowing your classes the rest of the answer will be kind of a guess-work:
Assuming you have a fromJson in place, then you can map your data like the following:
const myDocuments: Document[] = myJson.documents.map(Document.fromJson);
And the fromJson-method could look like this:
class Document {
constructor(public title: string, public versions: Version[])
public static fromJson(json: any): Document {
return new Document(
json.title,
json.versions.map(Version.fromJson)
);
}
}
class Version {
constructor(public fileSize: number) {}
public static fromJson(json: any): Version {
return new Version(json.fileSize);
}
}

Using *ngFor with a JSON object in Angular 2

I'm trying to implement a decoupled wordpress solution and I'm having a bit of confusion displaying the JSON object properties in my template. I'm able to return JSON objects for the WP API but not sure how to handle them. The only way I can get a property to display it's value in a template is if I add a [0] to the interpolated property, which won't work in an ngFor loop. I've read the solution by #Thierry here access key and value of object using *ngFor
but this doesn't seem to be how Google handles the Tour of Heroes app http://plnkr.co/edit/WkY2YE54ShYZfzJLSkMX?p=preview
Google uses this data set:
{
"data": [
{ "id": "1", "name": "Windstorm" },
{ "id": "2", "name": "Bombasto" },
{ "id": "3", "name": "Magneta" },
{ "id": "4", "name": "Tornado" }
]
}
which looks like a JSON object to me, so how is the app able to handle something like this:
<ul>
<li *ngFor="let hero of heroes">
{{hero.name}}
</li>
</ul>
I'm just unclear if there's been a change in RC5 that allows iteration over an object, or do I still need to transform this somehow. I'm very new to Angular and could use a little guidance on this matter. Thanks!!
An update based on the comments, if I want to transform an api request like http://localhost:8888/wp-json/wp/v2/posts, what's the best method for that? My return code would look something like:
[
{
"id": 4,
"date": "2016-08-09T00:09:55",
"date_gmt": "2016-08-09T00:09:55",
"guid": {
"rendered": “http://localhost:8888/?p=4"
},
"modified": "2016-08-09T00:11:05",
"modified_gmt": "2016-08-09T00:11:05",
"slug": “wp-api-test”,
"type": "post",
"link": "http://localhost:8888/2016/08/wp-api-test”,
"title": {
"rendered": "testing the wp api"
},
"content": {
"rendered": "<p>loreum ipsum</p>\n"
},
"excerpt": {
"rendered": "<p>loreum ipsum</p>\n"
},
"author": 1,
"featured_media": 0,
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"format": "standard",
"categories": [
1
],
}
]
Without writing all the code for you, there is no short answer to what you are asking, but here are some tips:
You have to take the JSON response you are getting back and create either an interface or class in TypeScript so when you perform the POST, Angular 2 can take the JSON and convert it to an object using your classes.
JSON to TS generator: http://json2ts.com/
Ninja Tips 2 - Make your JSON typed with TypeScript - http://blog.ninja-squad.com/2016/03/15/ninja-tips-2-type-your-json-with-typescript/
TypeScript Json Mapper - http://cloudmark.github.io/Json-Mapping/
How are you defining your services?
Here's an example:
export interface IPost {
id: number;
date: Date;
date_gmt: Date;
... // rest of your defintion
}
#Injectable()
export class BlogPostService {
private http: Http;
constructor(http: Http) {
this.http = http;
}
private apiUrl: string = 'api/blog/posts.json';
getPosts(): Observable<IPost[]> {
return (this.http.get(this.apiUrl)
.map((response: Response) => <IPost[]>response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError)) as any;
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || "Server error");
}
}
This line should transform your json object to array[] of IPosts
.map((response: Response) => <IPost[]>response.json())
Hope that helps.
Thanks so much for the answers. They helped lead me to the solution. I was able to solve this rather simply by creating a posts array and making it equal to the Observable return. The component looks like this:
posts: {};
constructor (private _wpService: WpApiService) {}
ngOnInit() { this.getPosts() }
getPosts() {
this._wpService.getPosts()
.subscribe(
data => {
this.posts = data;
});
}
The template looks like:
<li *ngFor="let post of posts">
<h3>{{post.title.rendered}}</h3>
</li>
Just replace {{hero.name}} by {{hero.data.name}}
The best way to handle the JSON object by creating an interface class to access the data easily