How to map an object from JSON file to another object? - json

Here is my json file
{
"data": [
{
"firstName": "Tom",
"lastName": "Yoda",
"type": "guest",
"id": "0",
"gender": m,
"data": { "age": 26, "born": "UK" }
},
]
}
This data array could have more entries.
I have to map the values into an interface which looks like:
InterfacePerson {
id: string;
title: string;
firstName: string;
lastName: string;
age: string;
location: string;
}
I am unable to change the interface. So I'm trying to do some pseudo coding.
const list;
list = convertToInterfacePerson = (value): Array<InterfacePerson> => {
return {
id: value.id,
title: if(value.gender === "m")? "Mr" : "Mrs",
firstName: value.firstName,
lastName: value.lastName,
age: value.data.age,
//...
}
}

I think you were trying to use a conversion mapping function called convertToInterfacePerson but you hadn't set it up yet (separately from trying to use it). The code below shows it declared and used within a map Array method call. I believe this resolves the error(s) you were getting.
// Copied in the JSON for demonstration
const sourceJson = {
"data": [
{
"firstName": "Tom",
"lastName": "Yoda",
"type": "guest",
"id": "0",
"gender": "m",
"data": { "age": 26, "born": "UK" }
},
]
};
// Declared the InterfacePerson interface
interface InterfacePerson {
id: string;
title: string;
firstName: string;
lastName: string;
age: string;
location: string;
}
// Declared the conversion mapping function (optional parameter typing included)
const convertToInterfacePerson = (value: { firstName: string, lastName: string, type: string, id: string, gender: string, data: { age: number, born: string } }): InterfacePerson => {
return {
id: value.id,
// Removed the `if` statement due to ternary conditional
title: ((value.gender === "m") ? "Mr" : "Mrs"),
firstName: value.firstName,
lastName: value.lastName,
// Wrapped the value.data.age in a string conversion
age: String(value.data.age),
location: value.data.born
};
}
// Declared and assigned the list based on the returned array from the mapping function (each element is applied in the `convertToInterfacePerson` function)
const list = sourceJson.data.map(convertToInterfacePerson);
// Show the result of the conversion
console.log(JSON.stringify(list, null, 2));
And for a live example, check out this TypeScript Playground script containing this solution.

Related

Transform json to class intstance with class-transformer

I would like to create an instance of the Customer class from Json object.
But using the plainToInstance function of class-transformer I don't have the proper class instance as a type save typescript object.
What I'm doing bad?
Import
import { plainToInstance } from 'class-transformer';
Customer JSON
const json = `{
"id": "1",
"name": "Jogn",
"surname": "Doe",
"email": "j.doe.test#gmail.com",
"phone": "123456789"
}
}
`;
Customer class definition
import { Field, ObjectType, Directive, ID } from '#nestjs/graphql';
import { Address } from './address';
#ObjectType()
#Directive('#key(fields: "id")')
export class Customer {
#Field(() => ID)
id: string;
#Field()
name: String;
#Field({nullable: true})
surname?: String;
#Field()
email: String;
#Field({nullable: true})
phone?: String;
#Field()
customerType: String;
#Field()
customerStatus: String;
#Field(() => [Address], { nullable: true })
addresses?: [Address]
}
Transformation from Json to Customer instance
let customer : Customer = plainToInstance(Customer, json) as Customer;
console.log('customer.email);
Console result
Customer email: undefined
So I couldn't get the email of the customer here
This is what I have when I log the entire customer variable
console.log(customer);
{
"id": "1",
"name": "Jogn",
"surname": "Doe",
"email": "j.doe.test#gmail.com",
"phone": "123456789"
}
Test with creating the Customer instance inline
var x = new Customer();
x.id = "123";
console.log(x)
So, now the object looks properly in the console
Customer { id: '123' }
You must pass a json object to plainToInstance - not a string.
i.e. your json variable should be
const json = {
id: '1',
name: 'Jogn',
surname: 'Doe',
email: 'j.doe.test#gmail.com',
phone: '123456789',
};
here's a working Stackblitz example
The second attribute of plainToInstance should be a plain object so you have to parse your json string into an object:
let customer = plainToInstance(Customer, JSON.parse(json))

Converting json object to typescript interface causing error in the mock object while unit testing in Angular 11

I am receiving a json response in an Angular 11 app and I have created an interface corresponding to that json object. The json object is
{
"division": {
"uid": "f5a10d90-60d6-4937-b917-1d809bd180b4",
"name": "Sales Division",
"title": "Sales",
"type": "Form",
"formFields": [
{
"id": 1,
"name": "firstName",
"label": "First Name",
"value": "John"
},
{
"id": 2,
"name": "lastName",
"label": "Last Name",
"value": "Smith"
}
]
}
}
The typescript interface I created for this json object is
export interface FormField {
id: number;
name: string;
label: string;
value: string;
}
export interface Division {
uid: string;
name: string;
title: string;
type: string;
formFields: FormField[];
}
export interface Division {
division: Division;
}
I am using a service division.sevice.ts to fetch the above json response from API and everything works fine. I am trying to write unit tests for the this service in the division.service.spec.ts file. I created a mockDivisionObj inside this file for testing purpose which is shown below.
mockDivisionObj = {
"division": {
"uid": "f5a10d90-60d6-4937-b917-1d809bd180b4",
"name": "Sales Division",
"title": "Sales",
"type": "Form",
"formFields": [
{
"id": 1,
"name": "firstName",
"label": "First Name",
"value": "John"
},
{
"id": 2,
"name": "lastName",
"label": "Last Name",
"value": "Smith"
}
]
}
}
An error is shown which says
Property 'division' is missing in type '{ uid: string; name: string; title: string; type:
string; formFields: { id: number; name: string; label: string; value: string; }[]; }' but
required in type 'Division'.
I think the way I created the interface may be wrong but I couldn't figure out what exactly is causing the issue. Please help me out with this.
I was able to fix the issue by changing the name of one of the interfaces in the file to 'AppDivision' as shown below.
export interface FormField {
id: number;
name: string;
label: string;
value: string;
}
export interface Division {
uid: string;
name: string;
title: string;
type: string;
formFields: FormField[];
}
export interface AppDivision {
division: Division;
}
The same name for two interfaces caused the error in the unit test mock object.
Your code is fine.To solve this error you can try the code below =>
this.division = this.mockDivisionObj.division as Division;
Check the Link: StackBlitz Demo link.

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);

JSON object interfaced return undefined

i want to create a pipe in Angular 9 that translate my table words in various language.
I have created a JSON file that contains a key and the value for a translation service. I have also created some interfaces for this json file.
translate.json
{
"lang":[
{
"IT": [
{ "name": "Nome" },
{ "surname": "Cognome" },
{ "email": "E-mail" },
{ "cf": "Codice fiscale" },
{ "phone": "Cellulare" },
{ "age": "Età" },
{ "city": "Città" },
{ "job": "Lavoro" }
]
},
{
"EN": [
{ "name": "first name" },
{ "surname": "last name" },
{ "email": "E-mail" },
{ "cf": "Fiscal code" },
{ "phone": "Phone" },
{ "age": "Age" },
{ "city": "City" },
{ "job": "Job" }
]
}
]
}
translateInterface.ts
export interface Lang {
lang: (Langs)[];
}
export interface Langs {
IT: (ITEntityOrENEntity)[];
EN: (ITEntityOrENEntity)[];
}
export interface ITEntityOrENEntity {
name: string;
surname: string;
email: string;
cf: string;
phone: string;
age: string;
city: string;
job: string;
}
translate.service.ts
translate(key: string, lang:string) {
return this.http.get<Langs>('assets/json/translate.json').subscribe((res: Lang) => console.log(res))
}
I have updated the json and the interface, now how i can return one object of the IT array?
I see multiple issues.
You don't need to define the properties IT and EN as arrays in the JSON file. It could very well be plain JS objects.
{
"IT": {
"name": "Nome",
"surname": "Cognome",
"email": "E-mail",
"cf": "Codice fiscale",
"phone": "Cellulare",
"age": "Età",
"city": "Città",
"job": "Lavoro"
},
"EN": {
"name": "first name",
"surname": "last name",
"email": "E-mail",
"cf": "Fiscal code",
"phone": "Phone",
"age": "Age",
"city": "City",
"job": "Job"
}
}
There is no need for two different interfaces. You could assign one single interface.
export interface Details {
name: string;
surname: string;
email: string;
cf: string;
phone: string;
age: string;
city: string;
job: string;
}
You are defining the type as array in Langs interface instead of the defined details interface. You could do something like
export interface Langs {
IT: Details;
EN: Details;
}
At the moment you're wrongfully returning the subscription instead of the observable from the function. You could return the observable from the service and subscribe to it the component controller.
Service
translate(language: string): Observable<Details> {
return this.http.get<Langs>('assets/json/translate.json').pipe(
map(response => response[language])
);
}
Component
ngOnInit() {
this.translateService.translate('IT').subscribe(
details => { this.details = details },
error => { }
);
}
Template
<span>{{ details?.name }}</span>
<span>{{ details?.surname }}</span>
<span>{{ details?.email }}</span>
...
Working example: Stackblitz

Json error - Cannot access child value on newtonsoft.json.linq.jproperty.

I have the following Json -
Property {
id: 122334,
source:
[ id : 123,
address:
{
city: "little rock",
state: "Arkansas",
country: "USA"
},
unit:
{
id: 222,
name: "The wall",
count: 2
}, ]
[ {id: 8889,
address:
{
city: "milka",
state: "Arkansas",
country: "USA"
},
unit:
{
id: 555,
name: "The watt",
count: 3
},
},
]
}
I am parsing it the following way -
string data = client.DownloadString(URL);
JToken token = JObject.Parse(data);
if (!string.IsNullOrEmpty(Convert.ToString(token["property"].Children())))
{
token["property"].Children().ToList().ForEach(child =>
{
string GetID = Convert.ToString(child["source"]["unit"]["id"]);
if (GetID == id)
{
//move rest of the code here
}
else
{
}
});
}
But I get the execption - cannot access child value on newtonsoft.json.linq.jproperty.
at the line -
string GetID = Convert.ToString(child["source"]["unit"]["id"]);
What am I doing wrong?
enter code here