Create model for JSON in Angular 9 - json

I want to model this api response; as you see for each id we should create a property and add to object model
API response is :
{
"result": {
"id_8knimfclf": {
"text1": "X^2 is a function.",
"type": "truefalse",
"choices": ["true", "false"],
"marks": 1,
"answer": "false"
},
"id_8knimfcle": {
"text1": "Which one is true?",
"type": "multichoice",
"choices": ["first", "second", "third"],
"marks": 3,
"answer": "first"
},
....there are a lot of id due to user data enterance
}
}
I create something like this:
export interface details{
text1?string;
type?:string;
marks?:string;
choices?:string[];
answer?:string;
}
export class model{
id?:string;
detail?:details;
constructor(id:string,detail:details){
this.id=id;
this.details=detail;
}
}
but the output json file an array of object like below
[
{id:"id_8knimfclf",
details:{"text1": "X^2 is a function.","type": "truefalse","marks": 1,"choices": ["true", "false"],"answer": "false"}},
{id:"id_8knimfcle",
details:{"text1": "Which one is true","type": "multichoice","marks": 1,"choices": ["first", "second", "third"],"answer": "false"}},
//other id
]
Any help is appreciated

The problem is that when you convert an object to JSON the name of property becomes the key of the json.
If i take the example array of elements you provided and i run it in json2ts i have the following output models:
export interface Id8knimfclf {
text1: string;
type: string;
choices: string[];
marks: number;
answer: string;
}
export interface Id8knimfcle {
text1: string;
type: string;
choices: string[];
marks: number;
answer: string;
}
export interface Result {
id_8knimfclf: Id8knimfclf;
id_8knimfcle: Id8knimfcle;
}
export interface RootObject {
result: Result;
}
But i imagine it's not very useful to create a interface/model of every possible "id" of your list, also because probably you don't know which values you will have.
So we can use a trick that come from javascript and a loose object in which we can assign the name of the property dynamically instead of the value
Let's create out loose object
export interface Result {
[key: string]: details;
}
To use it to define the property name with the id values
private convertToJson(models: model[]): string {
const results: Result[] = [];
for (let model of models) {
let result: Result = {};
result[model.id] = model.details;
results.push(result);
}
return JSON.stringify(results);
}
So if you provide this input to the convertToJson function
[
{
id: "id_8knimfclf",
details: {
text1: "X^2 is a function.",
type: "truefalse",
marks: 1,
choices: ["true", "false"],
answer: "false"
}
},
{
id: "id_8knimfcle",
details: {
text1: "Which one is true",
type: "multichoice",
marks: 1,
choices: ["first", "second", "third"],
answer: "false"
}
}
]
You will have the JSON you looking for as output:
[{"id_8knimfclf":{"text1":"X^2 is a function.","type":"truefalse","marks":1,"choices":["true","false"],"answer":"false"}},{"id_8knimfcle":{"text1":"Which one is true","type":"multichoice","marks":1,"choices":["first","second","third"],"answer":"false"}}]
I have create this stackblitz example that prints the result in console.

Related

Angular how to handle a nested http response

My angular service returns the following type of response:
{
"name": "abc",
"id": 1,
"list": [
{
"name": "listName1",
"id": 1
},
{
"name": "listName2",
"id": 2
}
]
}
This is what the call in the service looks like:
fetchX(): Observable<X> {
return this.http.get<X>(some_url)
}
Now, in my component I can access the 'name' and 'id' attribute of the returned object, but for the 'list', which is a list itself, I only get 'undefined'. I'm displaying the list elements in my application (by their name), and they don't actually show up there either (the HTML part for this is definitely correct, this isn't the issue).
myX: CustomX
myList: CustomList[]
ngOnInit() {
this.service.fetchX().subscribe((response) => {
this.myX = response,
this.myList = response.list,
console.log(response.name), //returns 'abc'
console.log(response.id), //returns '1'
console.log(response.list) //returns 'undefined'})}
The entities look like this:
export class CustomX {
name: string
id: number
list: CustomList[]
}
class CustomList {
name: string
id: number
}
What am I missing? I think I may be handling the response in the service incorrectly.

initialize json file data as a TypeScript Map

as a young typescript padawan
i am trying to parse mock data from a json witch involves initializing a Map<string, MenuPageData>
and i get an error (attached below)
i would like to be able to supply the correct data format in the json or map it properly from the existing data.
here is the error:
here is the code:
export interface MenuItem {
data: {
id: string;
name: string;
currency?: string;
imageUrl?: string;
description?: string;
price?: number;
};
}
export interface MenuPageData {
pageName: string;
menuItems: MenuItem[];
}
export interface MenuPageDataCollection {
menuPages: Map<string, MenuPageData>;
}
the error is comming from "(pagesDataMock.menuPages)"
const dataCollection: MenuPageDataCollection = { menuPages: new Map<string, MenuPageData>(pagesDataMock.menuPages) };
export const menuPagesCollection: () => MenuPageDataCollection = (): MenuPageDataCollection => {
return dataCollection;
};
and here is the json source:
{
"menuPages": [
"mealPage1",
{
"pageName": "menuPage1",
"menuItems": [
{
"data": {
"id": "null0",
"name": "meal",
"currency": "EUR",
"imageUrl": "../images/greenHand.jpg",
"description": "tasty",
"price": 12
}
},
{
"data": {
"id": "null0",
"name": "meal",
"currency": "EUR",
"imageUrl": "../images/greenHand.jpg",
"description": "tasty",
"price": 12
}
}
]
},
"mealPage2",
{
"pageName": "menuPage1",
"menuItems": [
{
"data": {
"id": "null0",
"name": "meal",
"currency": "EUR",
"imageUrl": "../images/greenHand.jpg",
"description": "tasty",
"price": 12
}
},
{
"data": {
"id": "null0",
"name": "meal",
"currency": "EUR",
"imageUrl": "../images/greenHand.jpg",
"description": "tasty",
"price": 12
}
}
]
}
]
}
i would appreciate and feedback, i tried several different ways of doing it but now 3-4 days passed by and i am running on empty of understanding
Map is a rather strong constraint that is not representable in JSON as is. First you'll have to validate the input is satisfying the requirements for your Map<string, MenuPageData>. Then to make it understandable by TS wrap in into type guard or type assert function. And finally convert it into the actual Map object yourself.
Simplified example:
interface IFace {
prop: string
}
interface Res {
title: string
ifaceMap: Map<string, IFace>
}
interface ResJSON {
title: string
ifaceMap: { [K in string]: IFace }
}
function assertResponse(json: unknown): asserts json is ResJSON {
...
}
function convert2Res(res: ResJSON): Res {
const { title, ifaceMap } = res
const map = new Map()
for(let key in ifaceMap) map.set(key, ifaceMap[key])
return { title, ifaceMap: map }
}
assertResponse(goodResponse)
const mapRes = convert2Res(goodResponse)
TS playground
In case you have full control of the source json and absolutely sure it may never be misshaped you may completely skip the assert part and feed the response (forcibly asserted to ResJSON type) right into convert2Res.

Moshi parse json with different key

I was looking towards PolymorphicAdapter but all the polymorphic example I could find had a key called "type" or something similar that could be use to differentiate the class to use. However in my case I don't have such key. I'm a bit lost on how to parse such a peculiar json.
{
"infos": {
"1588318": {
"id": "1588318",
"id_user": "9701",
"profile_name": "Profile1",
"views": 100
},
"1588319": {
"id": "1588319",
"id_user": "7391",
"profile_name": "Profile2",
"views": 10
},
"1588320": false,
"1588321": {
"id": "1588321",
"deleted": true
}
}
}
data class UserInfo(val infos: Map<String, UserResult>)
sealed class UserResult {
data class UserDeleted(val id: String, val deleted: Boolean): UserResult()
data class UserInfoCard(
val id: String,
val title: String,
#Json(name = "profile_name") val profileName: String,
val views: Int
): UserResult()
}
In the end I didn't find any solution and after discussing with the API manager he said he would update with a key to determine if it's either a profile or a deleted_profile

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

Change json data to Typescript interface objects in Angular 2

I have json data that is structured like this:
{
"timestamp": 1467471622,
"base": "USD",
"rates": {
"AED": 3.673027,
"AFN": 68.475,
"ALL": 123.095199,
"AMD": 476.8075,
"ANG": 1.78385,
"AOA": 165.846832,
"ARS": 15.05143,
"AUD": 1.333463,
"AWG": 1.793333,
"AZN": 1.553975,
"BAM": 1.757679,
"BBD": 2,
"BDT": 78.33184,
"BGN": 1.756683,
"BHD": 0.377337,
"BIF": 1660.642515,
"BMD": 1,
"BND": 1.344589,
How can I map this to muliple objects in typescript like this:
export interface Stock {
name: string;
value: number;
}
Thanks
let keys = Object.keys(data.rates);
let mapped: Stock[] = keys.map(key => {
return { name:key, value: data.rates[key] } as Stock
});
console.log(mapped);
https://jsfiddle.net/qfo43o24
You donot need to map manually. Your Typescript code can be:
export interface Stock{
timestamp : Number,
base : String,
rates : Rates
}
export class Rates{
AED : Number,
..... so on