Angular Js parse deeper JSON file - json

I am trying to parse an array inside an object. I tried to map the result to get the array but could not reach to the point of the array.
My JSON looks like this.
{
"id": 1,
"projectName": "Opera house",
"projectDescription": "This image was taken during my first photography course.",
"thumbnailImageName": "1.JPG",
"projectDetails": {
"id": 1,
"relatedPhotos": [
"1.JPG",
"2.JPG",
"3.JPG"
],
"location": "Sydney",
"scope": "Learn basic of photography",
"description": "Some description"
},
"favouriteProject": true
}
And I am mapping the HTTP response from a server like this.
this.projectService.getProjectDetailsByProjectName(projectName).subscribe(res =>
{
Object.keys(res).map(key => {
this.projectDetails = res[key];
})
});
The above mapping gives me the projectDetails object but cannot access the array inside it. While accessing the array, I get output three times. Two times undefined and finally the actual value. Can anyone guide me how to parse the above JSON file properly?
Thank you very much..
************Edited code****************
My code to get the http response and parse each object is as follows:
getSelectedProjectWithDetails(){
const projectName:string = this.activatedRoute.snapshot.paramMap.get("project-name");
this.projectService.getProjectDetailsByProjectName(projectName).subscribe(res => {
// console.log(res.relatedPhotos);
Object.keys(res).map( (key, value) => {
this.projectDetails = res[key];
console.log(this.projectDetails["relatedPhotos"])
})
})
}
I have project interface as
export interface project{
id:number;
projectName: string;
projectDescription: string;
favouriteProject: boolean;
thumbnailImageName: string;
projectDetail: projectDetail;
}
and projectDetails interface as:
export interface projectDetail{
id: number;
relatedPhotos: String [];
location: string;
scope: string;
description: string;
}
and http get request is
getProjectDetailsByProjectName(projectName: String): Observable<project>{
return this.http.get<project>("http://127.0.0.1:8080/project/"+projectName);
}

As an alternate you can user JSON.parse(res); after you have mapped your response from observable.
like this
Object.keys(res).map(key => {
JSON.parse(res);
this.projectDetails = res[key];
})
However I am using res.json();
addNewProduct(data: any): Observable<string> {
return this._http.post(this.addNewProdUrl, data).map(res => res.json());
}
Not sure what is the issue with your res.

You can use map() to transform HttpResponse body to JSON using json() method. Since response contains body, headers etc. json() can be used to only parse body.
Please look into below code to understand the same.
this.http.get('https://api.github.com/users')
.map(response => response.json())
.subscribe(data => console.log(data));
To know more, please refer documentation

Related

Access String array in Json

The API I am using has a nested string array it seems, I need to extract the path from it, but I cannot figure out how....
This is a break down of what I need to access.
the productimage is wrapped in quotes...
[
{title: "Item 1",
productimage: "[{"1":{"size":"75x75","path":"/10000/img.jpg"}]"
},
{title: "Item 2",
productimage: "[{"1":{"size":"75x75","path":"/20000/img.jpg"}]"
}
]
I am trying to access the image path...
The problem seems to be reading the string, I have attempted to treat it like an array, and a string and get mixed results..
Edited:
here is the entire productimages object, it is coming from an apache database that i have no control over.
productimages: "[{"1":{"size":"75x75","path":"/100000/101819-75x75-A.jpg"}},{"2":{"size":"222x222","path":"/100000/101819-600x600-A.jpg"}},{"3":{"size":"328x328","path":"/100000/101819-600x600-A.jpg"}}]"
my current axios call looks like this.
async function handleSubmit(searchData) {
if (searchData) {
const payload = searchData;
try {
const response = await axios({
url: `${baseUrl}q=*:*&fq=title:${payload}&fq=storeid:1234
method: "get",
});
//Set Hook
setData(response.data.response.docs);
} catch (error) {
console.error(error);
}
}
}
Here is the response data that is being set..
{productid: 1234, itemups: 1234, title: "productname", productimages: "[{"1":{"size":"75x75","path":"/100000/101819-75x75-A.jpg"}},{"2":{"size":"222x222","path":"/100000/101819-600x600-A.jpg"}},{"3":{"size":"328x328","path":"/100000/101819-600x600-A.jpg"}}]", productcount: 7}
I can get everything out of this, except the image.
You've to parse productimage:
const parsedArray = array.map(obj => {
let path = '';
try {
const productimage = JSON.parse(`${obj.productimage}`);
path = productimage[0].path
} catch(err) {
console.error(err)
}
return { ...obj, path }
});
[EDIT]
Axios response:
axios() // some axios call
.then(res => res.data)
.then(array => {
// ... here you can transform your array
})
Also make sure your json is properly formatted.
{
[
{"title": "Item 1",
"productimage": "[{"1":{"size":"75x75","path":"/10000/img.jpg"}]"
]
}

Deserializing json in Angular 2/4 using HttpClientModule

So I'm getting the following JSON structure from my asp.net core api:
{
"contentType": null,
"serializerSettings": null,
"statusCode": null,
"value": {
"productName": "Test",
"shortDescription": "Test 123",
"imageUri": "https://bla.com/bla",
"productCode": null,
"continuationToken": null
}
}
I have the following typescript function that invokes the API to get the above response:
public externalProduct: ProductVM;
getProductExternal(code: string): Observable<ProductVM> {
return this.http.get("api/product?productCode=" + code)
.map((data: ProductVM) => {
this.externalProduct = data; //not working...
console.log("DATA: " + data);
console.log("DATA: " + data['value']);
return data;
});
}
ProductVM:
export interface ProductVM {
productName: string;
shortDescription: string;
imageUri: string;
productCode: string;
continuationToken: string;
}
My problem is that I can't deserialize it to ProductVM. The console logs just produce [object Object]
How can I actually map the contents of the value in my json response to a ProductVM object?
Is it wrong to say that data is a ProductVM in the map function? I have tried lots of different combinations but I cannot get it to work!
I'm unsure whether I can somehow automatically tell angular to map the value array in the json response to a ProductVM object or if I should provide a constructor to the ProductVM class (it's an interface right now), and extract the specific values in the json manually?
The data object in the map method chained to http is considered a Object typed object. This type does not have the value member that you need to access and therefore, the type checker is not happy with it.
Objects that are typed (that are not any) can only be assigned to untyped objects or objects of the exact same type. Here, your data is of type Object and cannot be assigned to another object of type ProductVM.
One solution to bypass type checking is to cast your data object to a any untyped object. This will allow access to any method or member just like plain old Javascript.
getProductExternal(code: string): Observable<ProductVM> {
return this.http.get("api/product?productCode=" + code)
.map((data: any) => this.externalProduct = data.value);
}
Another solution is to change your API so that data can deliver its content with data.json(). That way, you won't have to bypass type checking since the json() method returns an untyped value.
Be carefull though as your any object wil not have methods of the ProductVM if you ever add them in the future. You will need to manually create an instance with new ProductVM() and Object.assign on it to gain access to the methods.
From angular documentation: Typechecking http response
You have to set the type of returned data when using new httpClient ( since angular 4.3 ) => this.http.get<ProductVM>(...
public externalProduct: ProductVM;
getProductExternal(code: string): Observable<ProductVM> {
return this.http.get<ProductVM>("api/product?productCode=" + code)
.map((data: ProductVM) => {
this.externalProduct = data; // should be allowed by typescript now
return data;
});
}
thus typescript should leave you in peace
Have you tried to replace
this.externalProduct = data;
with
this.externalProduct = data.json();
Hope it helps
getProductExternal(code: string): Observable<ProductVM> {
return this.http.get("api/product?productCode=" + code)
.map(data => {
this.externalProduct = <ProductVM>data;
console.log("DATA: " + this.externalProduct);
return data;
});
}
So, first we convert the response into a JSON.
I store it into response just to make it cleaner. Then, we have to navigate to value, because in your data value is the object that corresponds to ProductVM.
I would do it like this though:
Service
getProductExternal(code: string): Observable<ProductVM> {
return this.http.get(`api/product?productCode=${code}`)
.map(data => <ProductVM>data)
.catch((error: any) => Observable.throw(error.json().error || 'Server error'));
}
Component
this.subscription = this.myService.getProductExternal(code).subscribe(
product => this.externalProduct = product,
error => console.warn(error)
);
I used this approach in a client which uses the method
HttpClient.get<GENERIC>(...).
Now it is working. Anyway, I do not understand, why I do not receive a type of T back from the http client, if I don't use the solution provided in the answer above.
Here is the client:
// get
get<T>(url: string, params?: [{key: string, value: string}]): Observable<T> {
var requestParams = new HttpParams()
if (params != undefined) {
for (var kvp of params) {
params.push(kvp);
}
}
return this.httpClient.get<T>(url, {
observe: 'body',
headers: this.authHeaders,
params: requestParams
}).pipe(
map(
res => <T>res
)
);
}

Typescript GET object with date type

I have python REST API and angular2 on frontend. Now I need to parse GET request to objects Answer with date type field. Example of my json:
{
"date_answer": "2015/07/05",
"id": 1,
"text": "some text",
}
I use this code in controller:
getAnswers() : Observable<Answer[]> {
return this.http.get(this.answerUrl)
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));}
What I am trying to do is to solve my problem with parsing Date field in constructor like this:
export class Answer {
id: number;
text: string;
date_answer: Date;
constructor(
id: number,
text: string,
date_string: string
){
this.date_answer = new Date(date_string)
}
}
But this approach does't help. Maybe there are some better way to get date from json as Date type.
I'm using class-transformer by pleerock to achieve parsing.
Maybe you take a look at it.

Using Angular Observers to fetch data over a network

I'm working on an Angular app that contains a list of (financial) Trades that a user can add to. This has been going well, and I'm trying to switch over from a static list provided by a service to trying to fetch the data from a local Node.js server. I'm using an observer to asynchronously fetch the list of trades.
I've been following along with Angular's HTTP tutorial and the associated plunker. However, even though I can see the data coming from the server, I'm having trouble using the .subscribe() method to get a useful set of data out of it.
Here's my service which connects to the node server:
#Injectable()
export class TradeService {
private url = '...'; // URL to web API
tradeArray: Trade[] = [];
constructor(private http: Http) { }
//-----------GETTERS---------------//
getTradeObservable(): Observable<Trade> {
return this.http.get(this.url)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
console.log("body:" + body);
console.log("Entire Body.trades: " + body.trades);
return body.trades;
}
getTrades(): any {
this.getTradeObservable()
.subscribe(
trade => this.tradeArray.push(trade));
return this.tradeArray;
}
And here are the relevant portions the node server itself:
var TRADES = { "trades": [
{"id": 0, "cust": "Ben", "hasSub": true,
"subcust": "Rigby", "type": "s", "security": "001", "ticket": "99"},
...
{"id": 9, "cust": "Uber Bank", "hasSub": true,
"subcust": "Lil Bank", "type": "p", "security": "456", "ticket": "56"}
]};
////////////Get Requests/////////////////
//this route returns all data in JSON format
app.get('/', function(req, res) {
res.send(JSON.stringify(TRADES));
});
And the expected output from getTrades:
[
{id: 0, cust: "Ben", hasSub: true,
subCust: "Rigby", type: "s", security: '001', ticket: '99'},
...
{id: 9, cust: "Uber Bank", hasSub: true,
subCust: "Lil' Bank", type: "p", security: '456', ticket: '56'},
];
And one of the places the service is injected into and called:
export class SubmittedComponent {
constructor(private tradeService: TradeService) { }
//initally show all trades
rows = this.tradeService.getTrades();
...
I can see in the browser console that 'entire body.trades' is a full list of the data I want, but it seems subscribe is not pushing them into tradeArray, which ends up undefined.
Thank you for your time.
So I suppose that you are calling getTrades() from one of your components. If this is the case, this is what will happen:
The request will be sent
The request will be processed in the background asynchronously
The method will not wait for the request to be resolved and will return the current value of tradeArray, which is []
To avoid this, you could refactor you components so that they invoke the getTradeObservable() method an subscribe to the returned Observable.
UPDATE: Another option would be to refactor you service to use a Subject', and expose it to your components through anObservable`.
UPDATE: Assuming that you have the following definition for Trade
export interface Trade{
id: number;
cust: string;
hasSub: boolean;
subCust: string;
type: string;s
security: string;
ticket: string;
}
You could try the following approach
class TestComponent {
data: Trade[];
// inject service in component
getData(){
this.service.getTradesObservable().subscribe(data => this.data = data);
}
}
And change the definition of getTradesObservable to :
getTradeObservable(): Observable<Trade[]> {
return this.http.get(this.url)
.map(this.extractData)
.catch(this.handleError);
}
Speaking just about this portion of the code:
getTrades(): any {
this.getTradeObservable()
.subscribe(
trade => this.tradeArray.push(trade));
return this.tradeArray;
}
since getTradeObservable is asynchronous this line: return this.tradeArray; will (maybe) execute before the observable is resolved, you should remove getTrades method from your service and instead get a hold of the observable returned by getTradeObservable in your component and rather than expecting the whole thing to return the value you want, you should assign that value in the subscription like this:
#Component({
providers:[TradeService ]
})
export class myComponent{
trades:Trade[];
constructor(tradeService:TradeService){
tradeService.getTradeObservable().subscribe(tradeRes=>this.trades=tradeRes as Trade[]);
}
}

Saving data from JSON to object

I have a problem with pushing data from json to object.
This solution works for me but I am not happy with it. Look at the service.
Is there better way to save data from this json to object?
The json that i get from server looks like this:
{"documents": {"document": [
{
"id": 1,
"description": "Lorem ipsum",
"date": "2017-03-01"
},{
"id": 2,
"description": "Lorem ipsum",
"date": "2017-04-01"
}
]}}
My service:
downloadDocuments(id: number): Observable<DocumentsDTO[]>{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', this.authorizationService.basic);
let options = new RequestOptions({headers: headers});
let body = JSON.stringify(id);
return this.http
.post(DOCUMENTS_URL, body, options)
.map((response) => response.json().documents.document)
}
And component where I call this service:
documentsArray: Array<DocumentsDTO>;
downloadUserDocuments(id: number) {
this.documentsService.downloadDocuments(id)
.subscribe(documents =>{
if(documents !=null){
this.documentsArray = [];
documents.forEach((data) => {
this.documentsArray.push(data);
});
}
});
}
This solution works for me but I am not happy with .
Is there better way to save data from this json to array?
Service
return this.http
.post(DOCUMENTS_URL, body, options)
.map((res: Response) => {
res.json().map((obj) => {
new Document(obj.id, obj.description, obj.date)
})
})
This should return a collection of Documents
I'm not seeing how you could get past
.map((response) => response.json().documents.document)
This is just where your array is placed inside the response, period. You'd have to make changes to backend to change this.
What I am not understanding is why you are doing unnecessary iteration inside your subscribe, why not directly assign the array that is coming to your documentsArray? Like so:
this.documentsService.downloadDocuments(id)
.subscribe(documents => {
if(documents != null) {
this.documentsArray = documents;
}
});