1

I have an endpoint that returns this Json:

{
  "result": [
    {
      "id": 1,
      "name": "Kayak",
      "category": "Watersports",
      "description": "A boat for one person",
      "price": 27500,
      "currencyCode": "EUR"
    },
    {
      "id": 2,
      "name": "Lifejacket",
      "category": "Watersports",
      "description": "Protective and fashionable",
      "price": 48095,
      "currencyCode": "EUR"
    },
    {
      "id": 3,
      "name": "Soccer Ball",
      "category": "Soccer",
      "description": "FIFA-approved size and weight",
      "price": 1950,
      "currencyCode": "EUR"
    }
]
}

I have a class called Product in Angular:

import { Money, Currencies } from 'ts-money';

export class Product {
private money: Money;
public Amount = this.money.amount;

public constructor(
    public Id: number,
    public Name: string,
    public Category: string,
    public Price: number,
    public Description: string,
    public CurrencyCode: string) {
        this.money = new Money(Price, CurrencyCode);
    }

public GetPrice(): Money {
    return this.money;
}
}

I made this code in Angular:

export class ProductComponent implements OnInit {

  constructor(private datasource: ProductDataSource) {
  }

  private products: Product[];

  ngOnInit(): void {
    this.datasource.GetProducts()
    .subscribe((data) => {
        this.products = data;
    });
  }
 }
}

This code successfully returns an array of JSON objects that have the same properties as Product. Now, when I subscribe to this observable:

this.datasource.GetProducts()
.subscribe((data) => {
    // this.products is a class property of type Product[]
    this.products = data; // How do I make this work?
});

I can not figure out how to make the transition from JSON object to Angular class. My HTML page does not recognize this.products as an array of Product objects. What do I do?

1
  • How is declared / initialized this.products in your component and how are you using it in your template? Can you add this to your question please? Commented Jan 15, 2020 at 10:32

5 Answers 5

4

I think it's because of your mapping in your product class and also the type of your class, try to change class Product to interface Product

like this

    export interface Product{

    public id: number;
    public name: string;
    public category: string;
    public price: number;
    public description: string;
    public currencyCode: string; 

 }

you can go take a look at Angular : Class and Interface for the differences between class and interface

EDIT : (as you can see in my code, I also changed the variable name to match with your JSON response)

Sign up to request clarification or add additional context in comments.

Comments

2

Another approach could be to make JSON data, compatible with your Product class. You could use the map rxjs operator to transform your JSON data into Product. Modify the get products code, like this

    const source$ = of(result).pipe(pluck('result'),map(item=> item.map(x=>{
      let product = new Product(x.id,x.name, x.category, x.price, x.description, x.currencyCode);
      return product;
    })));

Here is a StackBlitz link.

2 Comments

rxjs is a good approach, but using it with a of is odd. You may do the same thing inside datasource.GetProducts() method (which is not detailed in the question), directly on the http call
Yes. Actually I just wrote this as an example only to reproduce the scenario in my stackblitz code.
1

Product properties names and json properties names doesn't match. You can do it like this:

this.datasource.GetProducts()
  .subscribe((data) => {
    // this.products is a class property of type Product[]
    this.products = (data || []).map(item => new Product(item.id, item.name, item.category, item.price, item.description, item.currencyCode))
  });

8 Comments

It's more easy to change product from class to interface and do the correct JSON mapping inside the interface, this map add complexity for nothing
totally agree, but mapping still an option too
you may also do new Product(item) and move the complexity inside the constructor...
I didn't say it wasn't an option, I think there is better way to do so :)
@Random, if properties names in Product and json doesn't match (as we have in a question. Product properties names are Capitalized) - this will not work.
|
0

create product interface with variables and use that interface to create array

    export interface Product{
      public Id: number,
      public Name: string,
      public Category: string,
      public Price: number,
      public Description: string,
      public CurrencyCode: string
    }

     products:Product[];

2 Comments

@Random it depend on how your project is set up, from the JSON you can see it's camelCase and not PascalCase
I'm talking about interface name, not attributes. Indeed attributes name depends on what the server responds, but should be camelCase (where in the question, attributes are PascalCase which is odd)
0

Change class to interface and change the case of also.

export interface Product{

public id: number;
public name: string;
public category: string;
public price: number;
public description: string;
public currencyCode: string; }

1 Comment

"just", but also change "class" to "interface"... ^^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.