Reputation: 766
I'm having real trouble converting a JSON array to collection of objects in Angular. I've not used Angular for some time, please forgive me if any of my terminology is incorrect.
I have the following products.json file in my project:
[
{
"id": 1,
"name": "Pen",
"description": "The finest blue pen.",
"relatedProducts": [2]
},
{
"id": 2,
"name": "A4 Paper",
"description": "A4 sized printer paper.",
"relatedProducts": [1]
}
]
This product.ts file:
export class Product {
Id: number;
Name: string;
Description: string;
RelatedProducts: Array<number>;
}
My app.component.ts file:
import * as ProductsJson from '../../json-data/products.json';
import { Component, OnInit } from '@angular/core';
import { Product } from 'src/app/models/product';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
productsJson: any = ProductsJson;
products: Array<Product>;
ngOnInit() {
this.products = <Product[]>this.productsJson;
console.log(this.products);
}
}
And finally my app.component.html:
<ul>
<li *ngFor="let p of products">
{{p.Id}} {{p.Name}}
</li>
</ul>
My console log shows the JSON data but it seems as though I'm making some error trying to convert it to a list of Product
objects. This is also preventing me from successfully using ngFor
in my view as the console error shows, so nothing shows on the page. How can I perform this conversion correctly so the loop works and this data is shown on the view?
Upvotes: 4
Views: 11620
Reputation: 343
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-hello-world',
templateUrl: './hello-world.component.html',
styleUrls: ['./hello-world.component.css'],
})
export class HelloWorldComponent implements OnInit {
jsonString: string = '[{"title":"test"},{"title":"test2"}]';
jsonObj: Array<object>;
jsonObj2: Array<object> = [{ title: 'test' }, { title: 'test2' }];
constructor() {
this.jsonObj = JSON.parse(this.jsonString);
this.jsonString = JSON.stringify(this.jsonObj2);
}
ngOnInit() {}
}
Upvotes: 0
Reputation: 3387
UPDATE 1 [ You can go declarative way of rxjs too ]..
Use of
operator of rxjs to create new stream of observable from your json file.
import {of} from 'rxjs'
productsJson = of <Product []>(ProductsJson);
export interface Product{
id: number;
name: string;
description: string;
relatedProducts: Array<number>;
}
and then in your template you can simply use async pipe
...
<ul>
<li *ngFor="let p of productsJson | async">
{{p.id}} {{p.name}}
</li>
</ul>
Update 2 [ You can simply use JSON.parse()
and JSON.stringify()
]..
productsJson: any = JSON.parse(JSON.stringify(ProductsJson));
and then use this in template like this...
<div *ngFor = "let item of productsJson">
<span> {{item.id }} </span>
</div>
Upvotes: 0
Reputation: 107
step by step:
Component.ts
The first, you have unuseless variables you have reduce keeping just one 'products' and initializing just like that the following code.
In ngOnInit()
you must to load the array initialized before. The way to do that is casting with type any cause importing from local json generates another data model, you have to access to the property 'default' and that's all.
import * as ProductsJson from '../../json-data/products.json';
import { Component, OnInit } from '@angular/core';
import { Product } from 'src/app/models/product';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
products: Array<Product> = new Array<Product>();
ngOnInit() {
this.products = (ProductsJson as any).default;
console.log(this.products);
}
}
Component.html
Another point to change is properties naming you have 'Id' & 'Name' instead of 'id' and 'name'.
<ul>
<li *ngFor="let p of products">
{{p.id}} {{p.name}}
</li>
</ul>
Entities
Product Class have to change the properties naming without Capital letters to have a correspondence with the Json Data or change Json data model to the Class anyway.
If I were you I will change also Product, using interface instead Class
export interface Product {
id: number;
name: string;
description: string;
relatedProducts: Array<number>;
}
Upvotes: 0
Reputation: 1591
you can use class-transformer which helps you to convert plain javascript objects to real es6 classes. With this real instances you can also use class methods.
import { Component, OnInit } from "@angular/core";
import ProductsJson from "./products.json";
import {plainToClass} from "class-transformer";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
productsJson: any = ProductsJson;
products: Array<Product>;
constructor() {}
ngOnInit() {
//this.products = <Product[]>this.productsJson;
this.products = plainToClass(Product, this.productsJson as []);
console.log(this.products);
}
}
export class Product {
id: number;
name: string;
description: string;
relatedProducts: Array<number>;
getId(){
return this.id + "_ID";
}
}
template:
<ul>
<li *ngFor="let p of products">
{{p.getId()}} {{p.id}} {{p.name}}
</li>
</ul>
Upvotes: 2
Reputation: 51
**- Use interface instead of class for Product.**
export interface Product {
id: number;
name: string;
description: string;
relatedProducts: number[];
}
**- If you need a class, then specify the parameterised constructor to assign variable values.**
export class Product {
id: number;
name: string;
description: string;
relatedProducts: number[];
constructor(product) {
this.id = product.id;
this.name: product.name;
this.description: product.description;
this.relatedProducts: product.relatedProducts;
}
}
**and then inside the component you can use**
this.products = new Product(this.productsJson); // if Product is a class
OR
this.products = this.productsJson; // if Product is an interface
Upvotes: 2
Reputation: 1271
Adding to Kushal Shah answer this also works.
import { Component, OnInit } from "@angular/core";
import ProductsJson from "./products.json";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
products = <Product[]>ProductsJson;;
constructor() {}
ngOnInit() {
console.log(this.products);
}
}
export class Product {
id: number;
name: string;
description: string;
relatedProducts: Array<number>;
}
Upvotes: 0
Reputation: 863
look at stackblitz
Let me know still you have an issue..
thanks
Upvotes: 2
Reputation: 222722
Your model should look like below,
export interface Product {
id: number;
name: string;
description: string;
relatedProducts: number[];
}
Change the products as
products: Product[];
and then,
this.products = this.productsJson;
Upvotes: 0