简体   繁体   中英

Convert JSON to object type in Angular

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?

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>

look at stackblitz

Let me know still you have an issue..

thanks

**- 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

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;

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

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

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>
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() {}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM