Having a JSON that looks like this
[
{
"Background": [
{
"Blue": 16.58
},
{
"Orange": 15.39
},
{
"Yellow": 14.0
},
{
"Pink": 14.74
},
...
]
},
{
"Type": [
{
"Brown": 12.89
},
{
"Gold": 6.8
},
{
"Robot": 6.75
},
...
]
},
{
"Body": [
{
"BlackBasic": 5.15
},
{
"Bathrobe": 5.85
},
...
]
},
...
]
I would like to have an interface for my angular app. I currently have:
export interface Attributes{
[key: string]: Array<Attribute>;
}
export interface Attribute {
[key: string]: number;
}
I have a fixed set of "top" categories, Background, Type, etc. and each top category has a fixed set of values, e.g. Background has the ones shown above (and more) etc.
Is there a way to have interfaces that allow only the subvalues, depending on the "top level"?
Hint: I have control over the structure of the json as well, if there is an easier way, I could also change the json.
since you have control over the json structure, you should modify it. Is there any reason you have an array at the top level? For me it seems that object would fit better. Also for your "top categories", you could also use object instead of array. There is no need to have an array of objects when they only contain one key.
example JSON:
{
"Background": {
"Blue": 16.58,
"Orange": 15.39,
"Yellow": 14,
"Pink": 14.74
},
"Type": {
"Brown": 12.89,
"Gold": 6.8,
"Robot": 6.75
},
"Body": {
"BlackBasic": 5.15,
"Bathrobe": 5.85
}
}
example interface:
export interface Background {
Blue: number;
Orange: number;
Yellow: number;
Pink: number;
}
export interface Type {
Brown: number;
Gold: number;
Robot: number;
}
export interface Body {
BlackBasic: number;
Bathrobe: number;
}
export interface RootObject {
Background: Background;
Type: Type;
Body: Body;
}
I changed your json model cause I think it's more readable:
{
"Background": {
"Blue": 16.58,
"Orange": 15.39,
"Yellow": 14.0,
"Pink": 14.74
},
"Type": {
"Brown": 12.89,
"Gold": 6.8,
"Robot": 6.75
},
"Body": {
"BlackBasic": 5.15,
"Bathrobe": 5.85
}
}
so in this model your interface would be like:
export interface Attributes {
[key: string]: Attribute;
}
export interface Attribute {
[key: string]: number;
}
Related
I am trying to create an accordion from the JSON data.
I am calling the GET request from json-server and successfully able to call the API.
I am not able to access the properties of the children in the variable tileData which shows the error:
Property 'children' does not exist on type 'Tile[]'.
Not sure where I am going wrong.
tileData!: Tile[];
getTileData() {
this.tileService.showTile().subscribe((data: any) => {
this.tileData = data;
console.log('this.tileData.children.name :>> ', this.tileData.children.name ); //Shows error
});
}
The function in service file is
showTile() {
return this.http.get<Tile[]>('http://localhost:3000/data');
}
I have created an interface to store the obtained JSON data which is shown below:
export interface Tile {
name: string;
image: string;
children: { name: string; image: string; url: string };
}
My JSON data received as follows:
{
"data": [
{
"name": "First",
"image": "https://img.freepik.com/free-vector/football-2022-tournament-cup-background_206725-604.jpg?size=626&ext=jpg",
"children": [
{
"name": "Firstone",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
},
{
"name": "Firsttwo",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
},
{
"name": "Firstthree",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
}
]
},
{
"name": "Second",
"image": "https://img.freepik.com/free-vector/football-2022-tournament-cup-background_206725-604.jpg?size=626&ext=jpg",
"children": [
{
"name": "Secondone",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
},
{
"name": "Secondtwo",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
},
{
"name": "Secondthree",
"image": "https://img.freepik.com/free-vector/hand-painted-watercolor-abstract-watercolor-background_23-2149005675.jpg?size=626&ext=jpg",
"url": "http://www.google.com"
}
]
}
]
}
Issue 1
Your JSON response was an object containing the data property with Tile[].
Use map from rxjs to return as Observable<Tile[]>.
import { map } from 'rxjs';
showTile() : Observable<Tile[]> {
return this.http.get<any>('http://localhost:3000/data')
.pipe(map((response: any) => response.data));
}
Issue 2
While the children property is an array but not an object.
export interface Tile {
name: string;
image: string;
children: { name: string; image: string; url: string }[];
}
Issue 3
To print out the name, you need to iterate titleData and iterate children array from each title object.
getTileData() {
this.tileService.showTile().subscribe((data: any) => {
this.tileData = data;
for (let title of this.tileData) {
for (let child of title.children) {
console.log('title.children.name :>> ', child.name);
}
}
});
}
Demo # StackBlitz
You haven't mentioned the error but, the interface definition should use exact name as you have in data.
try
export interface Tile {
name: string;
image: string;
children: { name: string; image: string; url: string };
}
I have tried to find solutions that I can understand with my knowledge level. But without success. I hope that others can benefit from this question.
Currently I am trying to understand how I provide data from different nested JSON files via interfaces and models. For my example, let's say I plan to have 3 JSON files in the future. (items.json, characters.json, monsters.json)
First, I'd like to find out what a clever JSON structure looks like. (There are many example tutorials, but I did not find any for such a special case as mine)
Wich one is smarter?
First variant:
{
"wearable": {
"torso": [
{
"name": "Schlachtrobe",
"defense": 7,
"price": 22
}
],
"head": [
{
"name": "stirnband",
"defense": 2,
"price": 50
}
],
"wrist": [
// etc...
]
},
"weapons": [
// etc...
],
"consumables": [
{
"name": "Bonbon",
"effect": "Heilt um 100 TP"
},
{
"name": "Schokolade",
"effect": "Heilt um 250 TP"
}
]
}
Second variant:
[
{
"id": 1,
"category": "wearable",
"type": "torso",
"name": "Schlachtrobe",
"defense": 7,
"price": 22
},
{
"id": 2,
"category": "wearable",
"type": "head",
"name": "stirnband",
"defense": 2,
"price": 50
},
{
"id": 3,
"category": "consumables",
"name": "Bonbon",
"effect": "Heilt um 100 TP"
},
{
"id": 4,
"category": "consumables",
"name": "Schokolade",
"effect": "Heilt um 250 TP"
}
]
The second variant makes it easier to attach items (for example in the future monsters.ts) to other items. In this case, e.g. just attach the id numbers. But then each item must use the same interface structure ... Then, for example, the "Bonbon" of the category "consumable" always has an empty number field called "defense" And this is just a similiar example. There will certainly be many more empty fields.
And what is about the interfaces and the Models? I try to solve this like this:
items.interface.ts
export interface ItemsInterface {
}
export interface ArmorsInterface {
name: string;
defense: number;
price: number;
}
export interface ConsumablesInterface {
name: string;
price: number;
effect: string;
}
item.model.ts
export class ItemsModel implements ItemsInterface {
}
export class ArmorsModel implements ArmorsInterface {
name: string;
defense: number;
price: number;
constructor(obj?: any) {
this.name = (obj && obj.name) ? obj.name : '';
this.defense = (obj && obj.defense) ? obj.defense : '';
this.price = (obj && obj.price) ? obj.price : '';
}
}
export class ConsumablesModel implements ConsumablesInterface {
name: string;
price: number;
effect: string;
constructor(obj?: any) {
this.name = (obj && obj.name) ? obj.name : '';
this.price = (obj && obj.price) ? obj.price : '';
this.effect = (obj && obj.effect) ? obj.effect : '';
}
}
These could then be used in the service like this:
#Injectable()
export class ItemsService {
private items;
private _armors: BehaviorSubject<ArmorsInterface> = new BehaviorSubject(new ArmorsModel());
private _consumables: BehaviorSubject<ConsumablesInterface> = new BehaviorSubject(new ConsumablesModel());
constructor(private http: HttpClient) {
this.loadItems();
}
get getArmors() {
return this._armors.asObservable();
}
get getConsumables() {
return this._consumables.asObservable();
}
loadItems() {
this.http.get(`./assets/data/items.json`).subscribe((items: ItemsInterface) => {
this.items = items;
this._armors.next(new ArmorsModel(items));
this._consumables.next(new ConsumablesModel(items));
});
}
}
There are certainly many mistakes in the service. I am still a beginner. ;)
And in the end how you could use the service:
export class SiteHomeComponent implements OnInit {
public armors: ArmorsInterface;
constructor(private iS: ItemsService) {
}
ngOnInit() {
// Returns the Data and write it in data
this.iS.getArmors.subscribe((data) => {
this.armors = data;
});
}
}
What can be done better? Or what would you do differently? I am grateful for everything that helps me to recognize my mistakes and to learn how to do it right. Thank you for your attention. :)
My data format is :
{
"_id": "593994b7163e6b0011c738cb",
"location_id": "58ec522a99da86001123ec47",
"customer_id": "premiereservices",
"user": {
"phone_num": "8587366808",
"balance": 98.05
},
"cart_total": 3,
"shopping_cart": {
"items": [
{
"barcode": "611269101713",
"description": "Red Bull Sugar Free 8.4oz",
"price": 3,
"taxable": false,
"tax_collected": 0
}
]
},
"Date": "2017-06-08T12:17:27.039Z",
"__v": 0
}
I am not able iterate data from "shopping_cart" and "user" need help on this issue.
Thanks.
to extract data from shopping_cart has items array so you will need a for loop here
For example:
let a = {
"shopping_cart": {
"items": [
{
"barcode": "611269101713",
"description": "Red Bull Sugar Free 8.4oz",
"price": 3,
"taxable": false,
"tax_collected": 0
}
]
}
}
if(a.shopping_cart.items.length) {
for(let i: number = 0; i < a.shopping_cart.items.length; i++) {
console.log(a.shopping_cart.items[i].barcode);
console.log(a.shopping_cart.items[i].description); /* etc you can here */
}
}
to extract data for user
let a = {
"user": {
"phone_num": "8587366808",
"balance": 98.05
},
}
console.log(a['user']['phone_num']) /* etc you can here */
Thanks all for your help.This is working for my requirement.
Here is working code:
import {Component} from 'angular2/core'
#Component({
selector: 'my-app',
template: `
<ul *ngFor="let object of data">
<li>
<ul *ngFor="let value of of ObjectKey(object)"><li> {{value.phone_num}}</li> </ul>
</li>
<li>
<ul *ngFor="let value1 of of ObjectKey(object.shopping_cart.items)"><li> {{value1.barcode}}</li> </ul>
</li>
</ul>
`,
directives: [],
styles: [`
`]
})
export class App {
ObjectKey(obj){
return Object.keys(obj).map((key)=>{ return obj[key]});
}
}
If it is json encoded then decode it pls..
Then
foreach(data.shopping_cart as item)
{
barcode=item[0]["barcode"];
description=item[0]["description"];
}
0 is the index
Create data.model.ts
import { User } from './user.model';
import { ShoppingCart } from './shopping-cart.model';
export class Data {
_id: string;
location_id: string;
customer_id: string;
user: User;
cart_total: number;
shopping_cart: ShoppingCart;
Date: string;
__v: number;
}
Create user.model.ts
export class User {
phone_num: string;
balance: number;
}
Create shopping-cart.model.ts
import { Item } from './item.model';
export class ShoppingCart {
items: Item[];
}
Create item.model.ts
export class Item {
barcode: string;
description: string;
price: number;
taxable: boolean;
tax_collected: number;
}
Then
let str: string = 'your json string';
let data: Data = JSON.parse(str);
console.log(data.user);
data.shopping_cart.items.forEach(item => {
console.log(item);
});
are you using android studio? If so I might be able to help I have been asking similary questions for 2 days now. we need more info but, your first step is probably going to be creating a json array to store the info like "JSONArray arr= new JSONArray(in here put your josn condition object, followed by a .toString() method)
i'm new to Typescript and javascript.
My question is:
how from this
```
{
"release": {
"ref": {},
"commits": {}
},
"debug": {
"ref": {},
"commits": {}
},
"feature": {
"ref": {},
"commits": {}
},
"hotfix": {
"ref": {},
"commits": {}
}
}
```
map it with with Typescript using interfaces
export interface IRepo {
branches: IBranch; // how to make branches a of type string: IBranch dictionary?
}
there will be unknown number of properties like debug, release, etc,
i want to keep them as dictionary in IRepo instance
i'm using this to fetch data:
```
getRepo() : Observable<IRepo> {
if (!this.repo) {
return this.http.get(this._baseUrl + 'repo.json')
.map((res: Response) => {
this.repo = res.json();
return this.repo;
})
.catch(this.handleError);
} else {
return this.createObservable(this.repo);
}
}
```
You have a map that goes from some known string to an object of known structure (has ref commits). Just use a string indexer:
interface BranchByName {
[branchName: string]: {
ref: any;
commits: any;
}
}
As part of my model I have this class in TypeScript:
module App.Model {
export class Unit {
id: number;
participantId: number;
name: string;
isProp: boolean;
}
}
In the controller, I need a a hash with the id as key:
module App.Controllers {
export class MyController {
public units: App.Model.Unit[];
populateDemoData() {
this.units = {
"1": { "id": 1, "participantId": 1, "name": "Testname", "isProp": true },
"2": { "id": 2, "participantId": 1, "name": "Another name", "isProp": false }
};
}
}
}
However, compiling the controller, I get the following error message:
Error 2 Cannot convert '{ }; [n: number]: App.Model.Unit; }' to ' }; [n: number]: App.Model.Unit; }' is missing property 'concat' from type 'App.Model.Unit[]'.
What am I doing wrong? And why is TypeScript asking for a concat property?
You defined units as an Array object, but assigned it a literal object. Just to clarify, a hash (a literal object) is not an array.
If all the IDs are an integer you can still use the array but it would be like this instead:
populateDemoData() {
this.units = [];
this.units[1] = { "id": 1, "participantId": 1, "name": "Testname", "isProp": true };
this.units[2] = { "id": 2, "participantId": 1, "name": "Another name", "isProp": false };
}
Edit:
Ok, you have to define a hash table to do that, but you also need to make App.Model.Unit an interface that matches your JSON objects.
module App.Model {
export interface Unit {
id: number;
participantId: number;
name: string;
isProp: boolean;
}
export interface UnitHashTable {
[id: string]: Unit;
}
}
module App.Controllers {
export class MyController {
public units: App.Model.UnitHashTable;
populateDemoData() {
this.units = {
"1": { "id": 1, "participantId": 1, "name": "Testname", "isProp": true },
"2": { "id": 2, "participantId": 1, "name": "Another name", "isProp": false }
};
}
}
}