Unable to show data of nested JSON file/model - json

I've currently got a local JSON file which holds the data for numerous properties. The idea is to load this JSON file into my app, and display it into a list with options to sort it (aka rearrange the data).
Here's my property.model.ts
export class Property {
ID: number;
description: string;
price: string;
agreementType: string;
streetName: string;
houseNumber: number;
postCode: string;
place: string;
image: Image[];
status: string;
constructionYear: number;
areaSize: number;
numberOfRooms: number;
numberOfBedrooms: number;
garageType: string;
garageCapacity: number;
}
export class Image {
ID: number;
base64: string;
}
This is what my json file looks like:
[
{
"ID": 1,
"description": "Lorem ipsum...",
"price": "€800,25",
"agreementType": "unknown",
"streetName": "street",
"houseNumber": 55,
"postCode": "postCode",
"place": "place",
"image": [
{
"ID": 1,
"base64": ""
},
{
"ID": 2,
"base64": ""
},
{
"ID": 3,
"base64": ""
}
],
"status": "status",
"constructionYear": 1999,
"areaSize": 50,
"numberOfRooms": 5,
"numberOfBedrooms": 2,
"garageType": "",
"garageCapacity": 0
},
{
//...
}
]
and here is my property.service.ts
export class PropertyService {
public propertyData: Observable<Property>;
constructor(private http: HttpClient) {
this.propertyData = this.observableJson();
}
observableJson() : Observable<Property> {
return this.http.get('/data/property.json')
.map((res:Response) => { res.json(); console.log(res.json())})
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
Later on, I want to be able to use my service elsewhere within the app as well, to (for instance) add a property object to it or something. Though I don't know if this is possible like that. But for now I just want to be able to somehow have my obserable array be useable in the property component. Which, at the moment, doesn't seem to work because when I use console.log(JSON.stringify(this.propertyData)); inside the constructor, I get the following error:
JS: ERROR Error: Uncaught (in promise): TypeError: Converting circular structure to JSON
JS: TypeError: Converting circular structure to JSON
now, a google search tells me that this is because it's a nested JSON object, but after many attempts I haven't been able to work out how to solve this.
Thanks in advance for any help.

The property Observable probably has something self-referential inside of it which results in the error you're seeing. You don't want to JSON.stringify propertyData which is an Observable, but you want to stringify the emitted JSON response. There are a lot of different ways to do this and it depends on the circumstances of where you are using it. For example:
this.propertyData.subscribe(data => JSON.stringify(data));
const data = JSON.stringify(await this.propertyData.toPromise());

Try this -
this.observableJson().subscribe(res => {
this.propertyData = res;
console.log(JSON.stringify(this.propertyData));
});

Related

How to create TypeScript class from Json data? [duplicate]

This question already has answers here:
How do I cast a JSON Object to a TypeScript class?
(28 answers)
How to parse a JSON object to a TypeScript Object
(11 answers)
How do I initialize a TypeScript Object with a JSON-Object?
(18 answers)
Closed 1 year ago.
I'm using Angular to call an external API. Json data is in format like:
[
{
"AccessGroupsIdList": [],
"FirstName": "Greg",
"LastName": "Tipton",
"LocationIdList": [],
"PermissionProfile": {
"Name": "Agent",
"PermissionProfileId": {
"ID": "xy678219-bd7c-103d-b56b-1f1234a85990"
},
"Type": 3
},
"ManagerName": "Gilchrist, George",
"Status": true,
"UserGroupID": {
"ID": "00000000-0000-0000-0000-000000000000"
},
"UserGroupName": "ROOT",
"UserId": {
"ID": "4445cc66-819a-4da0-8fbf-d0bb8ce65941"
}
}
]
How do I create a class in typescript to read it since json data is nested?
export class Employees
{
AccessGroupsIdList: string[];
FirstName: string;
LastName: string;
LocationIdList : number[];
PermissionProfile ??
ManagerName: string;
Status: boolean;
UserGroupID ??
UserGroupName : string;
UserId ??
}
Please guide if the PermissionProfile, PermissionProfile will be separate nested classes?
How do I declare those?
To extend Andrew Halil's answer, I would use interfaces instead of classes in your definitions, since there do not appear to be any class methods involved; you are just describing the shape of a JSON object returned from a server
export interface Employee
{
AccessGroupsIdList: string[];
FirstName: string;
LastName: string;
LocationIdList : number[];
PermissionProfile: PermissionProfile;
ManagerName: string;
Status: boolean;
UserGroupId: ID;
UserGroupName : string;
UserId: ID;
}
export interface PermissionProfile
{
name: string;
permissionProfileId: ID;
type: string;
}
export interface ID
{
id: string;
}
Now as for an implementation, I don't use Angular all that much but you would do something like this to get the items typed
async function listEmployees(): Promise<Employee[]> {
// Make a fetch call to the API endpoint
const data = await fetch('https://some-api-endpoint.web/employees')
// if the response comes back ok, return the JSON-ified response.
.then(res => {
if(res.ok) return res.json()
return [];
});
// Instruct typescript that "data" is to be treated as an array of Employee elements.
return data as Employee[]
}
Try declaring the Typescript class structures as follows:
export class Employees
{
AccessGroupsIdList: string[];
FirstName: string;
LastName: string;
LocationIdList : number[];
PermissionProfile: PermissionProfile;
ManagerName: string;
Status: boolean;
UserGroupId: UserGroupID;
UserGroupName : string;
UserId: UserID;
}
export class PermissionProfile
{
name: string;
permissionProfileId: PermissionProfileID;
type: string;
}
export class PermissionProfileID
{
id: string;
}
export class UserGroupID
{
id: string;
}
export class UserID
{
id: string;
}
I would suggest to name the property names consistently with an Id (e.g. with UserGroupId). The name and type class property names are valid in TypeScript (unlike with the C# syntax).

How to retrieve just one object from JSON file using TypeScript Angular?

I made a very normal HTTP request to get one object from a JSON file. but I noticed I get all the file's data instead of the only needed object.
following my code demonstrates how I made a class to fetch needed data but it still not working as planned for some reason.
JSON file (DB.json) => I need just (articles)
{
"articles": [
{
"id": "1",
"title": "Title 1",
"body": "what ever ... ",
"date": "14/03/2020",
"rating": 4,
"pic": "../../assets/images/cat.jpg"
},
{
"id": "2",
"title": "Title 2",
"body": "what ever ... ",
"date": "15/03/2020",
"rating": 5,
"pic": "../../assets/images/dog.jpg"
}
],
AnotherTableName [ ... etc ],
AnotherTableName [ ... etc ]
}
article.ts => the class
export class Article {
id: string;
title: string;
body: string;
date: Date;
rating: number;
pic: string;
}
component.ts
export class ArticleComponent implements OnInit {
constructor(private httpGetArticles: ArticleService) { }
errMess: string;
articles: Article[];
ngOnInit(){
this.httpGetArticles.getArticles().subscribe(
data => this.articles = data,
errmess => this.errMess = <any>errmess,
() => console.log(this.articles));
}
}
component.html
<p *ngFor="let artcl of articles">
<span>artcl.title</span>>
</p>
Service
getArticles(): Observable<Article[]> {
return this.http.get<Article[]>("./assets/DB.json")
.pipe(catchError(this.handleHttpErrService.handleError));
}
console.log( .. result
Object {
articles: Array [ {…}, {…} ]
feedback: Array(13) [ {…}, {…}, {…}, … ]
leaders: Array(4) [ {…}, {…}, {…}, … ]
promotions: (1) […]
Despite I get the object as shown, I got also the following error ( I think because I use NgFor for one object named articles but retrieved data come up with a different format "the whole JSON file" )
ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
So I need to retrieve the casted data only (articles) not all the JSON file
Ideally the backend should support returning specific properties of an object. For a quick fix you could pipe in RxJS pluck operator to the HTTP request in the client
Service
import { catchError, pluck } from 'rxjs/operators';
getArticles(): Observable<Article[]> {
return this.http.get<Article[]>("./assets/DB.json").pipe(
pluck('articles'),
catchError(this.handleHttpErrService.handleError)
);
}
In addition I'd also suggest the following changes.
Use TS interface instead of class for type checking. When to use an interface or a class in Typescript?
article.ts
export interface Article {
id: string;
title: string;
body: string;
date: Date;
rating: number;
pic: string;
}
Use async pipe in the component template instead of a subscription in the controller.
Component
import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
export class ArticleComponent implements OnInit {
constructor(private httpGetArticles: ArticleService) { }
articles$: Observable<Article[]>;
ngOnInit(){
this.articles$ = this.httpGetArticles.getArticles().pipe(
catchError(error => {
console.log('Error fetching articles:', error);
return throwError(error);
}
);
}
}
Template
<ng-container *ngIf="(articles$ | async) as articles">
<div *ngFor="let article of articles">
...
</div>
</ng-container>

JSON response cannot extract variables

Brand new to react-native and typescript!
I'm have a bit of trouble extracting JSON response. I was to extract the response and put it into a class as shown below.
Here is the request code
let notifications: INotification[]
notifications = (await Requests.GET('notification/user/test-user-1', accessToken));
Here is the class
export interface INotification {
id: string;
senderId: string;
receiverId: string;
text: string;
isSeen: boolean;
type: string;
timestamp: string;
}
Here is the Postman response
{
"notifications": [
{
"pk": "user-1",
"sk": "notification1234",
"entity": "notification",
"id": "id number",
"senderId": "test-user-2",
"receiverId": "test-user-1",
"text": "Test notifications",
"isSeen": false,
"type": 2
}
]
}
Here is response from the console
{ notifications:
[ { pk: 'user#test-user-1',
sk: 'notification1234',
entity: 'notification',
id: 'id number',
senderId: 'test-user-2',
receiverId: 'test-user-1',
text: 'Test notifications',
isSeen: false,
type: 2 } ]
}
I want to be able to write out:
console.log("TEXT: ",notifications[0].text )
And get the response of : "Text: Test notifications"
Any help welcome!
the data is in an array you need to pass the array first
console.log("TEXT: ", notifications[0].text);

Retrieve JSON Data In Angular 5

I am retrieving json data via http.get, my problem is that I cannot get a specific values of my key in typescript.
The data I am returning is in the format (json):
[
{
"id": 1,
"name": "Albany",
"manufacture": "Albany Superior Low Gi Sliced Brown Seed Bread 700g",
"price": 15.49,
"category": "Food",
"type": "Breads",
"image": "data:image/jpeg;base64,/9j/4AAQSkZJ..."
},
{
"id": 2,
"name": "Blue Ribbon",
"manufacture": "Blue Ribbon Brown Plus Low Gi Bread 700g",
"price": 13.99,
"category": "Food",
"type": "Breads",
"image": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
]
In Angular, my service is as below:
export class ProductService {
prodType:ProductModel;
productList:object;
prodList: Array<ProductModel> = [];
prodMap: Map<number, ProductModel>;
constructor( private http: HttpClient ) { }
getAllProducts(): Array<ProductModel>{
this.http.get<Array<ProductModel>>('/product/service/send/all/products').subscribe(
data => {
console.log( data );
},
error => {
console.error("HTTP FAILURE ERROR!!!");
}
);
return this.prodList;
}
getProductByType( productSearch:string ){
this.productList = this.prodList.find( x=> x.getType() == productSearch);
console.log( this.productList);
}
}
The ProductModel is as follows:
export class ProductModel {
private id: number;
private name: string;
private manufacture: string;
private price: number;
private category: string;
private type: string;
private image: string;
// get and setters
The million dollar question; let's say I would to search through my data for product types and only wanted to console-log products with type milk from my json data.
How would I do that? I have searched for similar solution, but they were unhelpful.
First assign the HTTP result to your class member and then filter your datas and then console.log the filtered array items.
export class ProductService {
prodType:ProductModel;
productList:object;
prodList: Array<ProductModel> = [];
prodMap: Map<number, ProductModel>;
constructor( private http: HttpClient ) { }
getAllProducts() {
this.http.get<Array<ProductModel>>('/product/service/send/all/products').subscribe(
datas => {
this.prodList = datas;
},
error => {
console.error("HTTP FAILURE ERROR!!!");
}
);
}
getProductByType( productSearch:string ): Array<ProductModel>{
let filteredProducts:Array<ProductModel> = this.prodList.filter(product => product.type == productSearch);
filteredProducts.forEach(product=> console.log(product);
return filteredProducts;
}
}
You can add the map and modify the response coming from the http get call and filter it before assigning it to the list . of if you want to separate the same then you need split the logic into two methods one to get the vanilla list and then filter the data on top of it
getAllProducts(): Array<ProductModel>{
return this.http.get<Array<ProductModel>>('/product/service/send/all/products').map(data => data.filter(value => value.type == 'milk')).subscribe() ;
}

Typescript JSON string to class

Let be this JSON string:
[
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
]
Let be this class:
export class MyObject{
id: number;
text: string;
}
How can I cast this JSON string to list of MyObject?
If I do:
console.log(<MyObject[]>JSON.parse(json_string));
It returns a list of Object instead of a list of MyObject
You don't necessarily need a class here. You can just use an interface
export interface MyObject{
id: number;
text: string;
}
Then you can just write:
var myObjArray : MyObject[] = [
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
];
If you data comes from the server, you will probably have it in a variable of type any, and you can just assign it to an array of that type and it will work as expected.
var data: any = getFromServer();
var myObjectArray:MyObject[] = data;
In typescript you don't need a class implementing an interface. Any object literal that satisfies the interface contract will do.
If your data is still in string for you can just use JSON.parse(jsonString) to parse the string to JavaScript objects.
See playground here
You will need to create a constructor for your class, and call it for each item in the list you receive.
export class MyObject{
constructor(public id: number, public text: string) { }
}
let data = [
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
];
let objects = data.map(o => new MyObject(o.id, o.text));
You can check it out in the playground here.
There is a problem when MyObject has 50 or more properties...
Add a constructor in your MyObject class so that it extends your json object.
export class MyObject {
constructor( json: any )
{
$.extend(this, json);
}
id : number;
text : string;
methodOnMyObject() {...}
}
In your ajax callback, create the MyObject object from your json Object:
let newObject = new MyObject( json );
newObject.methodOnMyObject();
I detailed the solution in that post.
One more way to achieve this:
var data: any = getFromServer();
var myObjectArray = data as MyObject;
Or:
var data: any = getFromServer();
var myObjectArray = <MyObject>dataMyObject;