HttpClient.get in Angular 5 is not returning data if data is in a nested json format. The code below works for non-nested json data.
Would you please let me know if I miss anything or what would be a way to get the data?
Code:
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
export class ReportService {...
searchByUser(userUrl: string): Observable<any> {
console.log('userUrl', userUrl);
return this.httpClient
.get(userUrl, { responseType: 'json' })
.catch((error: HttpErrorResponse) => {
return Observable.throw(error.status)
});
}
}
import { ReportService } from '../report.service';
this.reportService.searchByUser(userUrl).subscribe(data => {
console.log("Data :", data);
});
Nested JSON Sample Data returned by the userUrl:
[
{
"userId": "JX",
"location": "CHANTILLY, XX",
"fullName": "SMITH, JX L",
"userType": "P",
"userStatusDesc": "Active",
"occupationInfo": {
"occupationTitle": "HR GENERALIST HQ"
},
"miscInfo": {
"rankingPoints": 15,
"searchTermCount": 1
}
}
]
It looks like the issue was not with the HttpClient or nested JSON. I was able to have it working with the same JSON generated locally. And when I deployed the code it worked with the JSON generated under the same proxy.
Related
I'm using next.js and I want to fetch data from my data1.json file via getStaticProps(). The problem is that I get the error:
FetchError: invalid json response body at http://localhost:3000/data/data1.json reason: Unexpected token < in JSON at position 0
I have following code:
trainings.js (projectfolder/pages/trainings.js)
export default function Trainings({ data }) {
console.log(data);
return (
<main>
<h1>My trainings</h1>
</main>
);
}
export async function getServerSideProps() {
const res = await fetch('http://localhost:3000/data/data1.json');
const data = await res.json();
return { props: { data } };
}
data1.json (projectfolder/data/data1.json)
[
{
"name": "Jescie Duncan",
"email": "nunc#protonmail.couk",
"address": "Ap #666-9989 Nisi Avenue"
},
{
"name": "Karen Bartlett",
"email": "tellus.imperdiet#aol.couk",
"address": "P.O. Box 787, 2857 Tincidunt Ave"
},
{
"name": "Teegan Valdez",
"email": "lacus.mauris.non#hotmail.edu",
"address": "Ap #474-300 Nullam Avenue"
},
{
"name": "Stuart Silva",
"email": "nulla.donec.non#google.edu",
"address": "336-2367 Eu Ave"
}
]
Please check whether http://localhost:3000/data/data1.json api is working or not. Because Nextjs support React components as default support in the pages folder not JSON. If you want serve as API you need to use NextJS api routes which you need to specifically put logic inside api folder.
in api/data/data1.js file
import data from '/path/to/json'
async function handler(req, res) {
return res.status(200).json(data)
}
export default handler;
But a better approach is:
As you have JSON file, you directly import that data in trainings.js rather than calling an API.
import data from 'path/to/json';
export async function getServerSideProps() {
return { props: { data } };
}
I am trying to convert xml data to JSON in order to return it to my Angular app.
I've been able to get data but I'm not sure how to convert and return to Angular.
I am using xml2js parser plugin to convert xml.
node.js
router.get('/courselist', (req, res, next) => {
request("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml", function(error, response, body) {
console.log(body);
parser(body, function (err, result) {
res.json(response);
});
});
After parsing the output is like this:
{"gesmes:Envelope": {
"$": {
"xmlns:gesmes": "http://www.gesmes.org/xml/2002-08-01",
"xmlns": "http://www.ecb.int/vocabulary/2002-08-01/eurofxref"
},
"gesmes:subject": [
"Reference rates"
],
"gesmes:Sender": [
{
"gesmes:name": [
"European Central Bank"
]
}
],
"Cube": [
{
"Cube": [
{
"$": {
"time": "2017-09-21"
},
"Cube": [
{
"$": {
"currency": "USD",
"rate": "1.1905"
}
},
....
{
"$": {
"currency": "JPY",
"rate": "133.86"
}
},
]
}
]
}
]
}
}
Angular service
getCourseList() {
return this._http.get('./api/course-list').map(
(res: Response) => res.json()
).catch(this.handleError);
}
When I call the endpoint in Postman I can see parsed output, but in Angular I am getting error as I am not returning JSON object.
Unexpected token < in JSON at position 0
I've been looking around SO for a solution but not been able to find any which would suit me.
Can you please advise what am I doing wrong as I am beginner with Node.js
You angular service is calling './api/course-list' which is not a valid url. And, probably you have configured your server to return index.html page for even 404 page. That's why your angular client might be getting html page, and throwing the error while parsing it into `
Hope this._http.get('/api/course-list') fixes the issue.
I managed to find a solution I changed parsing to be response.body instead of body and it formatted XML properly.
Additionally paths in node.js and angular were not same.
router.get('/course-list', (req, res, next) => {
request("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml", function(error, response, body) {
var parsedBody;
var doneParsing = false;
parser(response.body, function (err, result) {
parsedBody = result;
doneParsing = true;
});
if (doneParsing === true) {
response.body = parsedBody;
}
res.json(response);
});
});
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
I am new to code Angular 2. My question is how to show JSON Format A with a proper formatting. As shown, the result includes whole objects (named Atom) I want to display.
If JSON format looks like B, I can show it using ngFor well. However, in the Json format A, I have to create multiple Atom objects explicitly from result then I can show them using NgFor.
I do not have sufficient knowledge about Angular 2 and JSON, if you have some idea about this, could you give me some guide for this and which way could be desirable solution?
Json Format A
{
"pageS": 25,
"pageN": 1,
"pageC": 2,
"result": [
{
"type": "A",
"id": "2425",
"tree": "false"
},
{
"type": "A",
"id": "1185",
"tree": "false"
},
{
"type": "A",
"id": "2680",
"tree": "false"
},
]
}
Json Format B
[
{"type":"A", "id": "2425", "tree":"false"},
{"type":"A", "id": "1185", "tree":"false"},
{"type":"A", "id": "2680", "tree":"false"}
]
app.component.ts
import {Component} from 'angular2/core';
import {Router} from 'angular2/router';
import {AtomService} from './service/atom';
import {User} from './datatype/User';
#Component({
selector: 'my-app',
template: `
<ul>
<li *ngFor="#atom of atoms">
{{atom.id}}
</li>
</ul>
`,
providers: [AtomService]
})
export class AppComponent {
atoms: Array<Atom>;
constructor(private service : AtomService) {
service.getAtoms().subscribe(res => this.atoms = res);
}
}
atom.service
import { Injectable } from 'angular2/core';
import { Http, Response } from 'angular2/http';
import 'rxjs/add/operator/map';
import {Atom} from '../datatype/Atom';
#Injectable()
export class AtomService {
constructor(private http: Http) {
this.http = http;
}
getAtoms() {
return this.http.get('./app/api/atoms.json')
.map( (responseData) => {
return responseData.json();
})
.map((atoms: Array<any>) => {
let result:Array<Atom> = [];
if (atoms) {
atoms.forEach((atom) => {
result.push(new Atom(atom.type, atom.id, atom.tree));
});
}
return result;
});
}
}
I'm not sure I understand what exactly do you want. You can read the results directly from the response, if you don't want to iterate and create new Atom objects.
<ul>
<li *ngFor="#atom of data.result">
{{atom.id}}
</li>
</ul>
But I think the way you have it now is actually better, as you should process the data, even though you can bind HTML directly to the result.
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