4

I'm new in the Angular2 world. For learning Angular I followed different tutorials and now I try to build a shop to learn more. But i get stuck right away.

I'm trying to get this model in to Angular: enter image description here

But I'm not succeeding. I get different errors like.

TypeError: Cannot read property 'description' of undefined and error TS2322: Type '{ ... }' is not assignable to type 'Product[]'.Type ...

This is what i got so far:

Product-type-attribute-model

export class ProductTypeAttribute {
id: number;
name: string;
content: string;
}

Product-type-model

import { ProductTypeAttribute } from './product-type-attribute.model';

export class ProductType {
    id: number;
    name: string;
    description: string;
    attributeTypes: ProductTypeAttribute[];
}

Product-model

import { ProductType} from './product-type.model';

export class Product  {
    id: number;
    name: string;
    description: string;
    image: string;
    price: number;
    type: ProductType;
}

Mock-product

import { Product } from './product.model';
import { ProductType } from './product-type.model';
import { ProductTypeAttribute } from './product-type-attribute.model';

export const productTypeAttributes: ProductTypeAttribute[] = [
    {
        id: 1,
        name: 'Kleur',
        content: 'test'
    },
    {
        id: 2,
        name: 'test',
        content: 'test'
    },
    {
        id: 3,
        name: 'test',
        content: 'test'
    },
    {
        id: 4,
        name: 'test',
        content: 'test'
    }
];

export const productTypeAttributes2: ProductTypeAttribute[] = [
    {
        id: 5,
        name: 'Kleur',
        content: 'test'
    },
    {
        id: 6,
        name: 'test',
        content: 'test'
    },
    {
        id: 7,
        name: 'test',
        content: 'test'
    },
    {
        id: 8,
        name: 'test',
        content: 'test'
    }
];

export const productType: ProductType =
    {
        id: 1,
        name: 'Type 1',
        description: 'Description of type 1',
        attributeTypes: productTypeAttributes
    };

export const productType2: ProductType =
    {
        id: 2,
        name: 'Type 2',
        description: 'Description of type 2',
        attributeTypes: productTypeAttributes2
    };

export const products: Product[] = [
    {
        id: 1,
        name: 'Product 1',
        description: 'Description of product 1',
        image: 'https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8',
        price: 15.15,
        type: productType
    },
    {
        id: 2,
        name: 'Product 2',
        description: 'Description of product 2',
        image: 'https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8',
        price: 15.15,
        type: productType
    },
    {
        id: 3,
        name: 'Product 3',
        description: 'Description of product 3',
        image: 'https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8',
        price: 15.15,
        type: productType2
    }
];

Product-service

import { Injectable } from '@angular/core';

import { Product } from './../shared/product.model';
import { products } from './../shared/mock-products';

@Injectable()
export class ProductService {
    getProducts(): Promise<Product[]> {
        return Promise.resolve(products);
    }

    getProduct(id: number): Promise<Product> {
        return this.getProducts().then(products => products.find(product => product.id === id));
    }
}

Product-component

import { Component, OnInit } from '@angular/core';
import { Product } from './../shared/product.model';
import { ProductService } from './../product/product.service';

@Component({
    selector: 'product',
    template: require('./product.component.html'),
    providers: [ProductService]
})

export class ProductComponent implements OnInit {
    product: Product;

    constructor(private productService: ProductService) { }

    getProduct(): void {
        this.productService.getProduct(1).then(product => this.product = product);
    }

    ngOnInit(): void {
        this.getProduct();
    }
}

Product HTML

<div class="product">
<div class="header">
        <h1>{{product?.name}}</h1>
        <h4></h4>
</div>

<figure>
    <img src="{{product?.image}}">
</figure>

<section>
    <p>{{product?.description}}</p>
    <details>
        <summary>Product Features</summary>
        <ul>
            <li *ngFor="let productAttribute of product?.type?.attributeTypes">
                {{productAttribute?.name}}
            </li>
        </ul>
    </details>
    <button>Buy Now</button>
</section>

I hope I explained my problem well and that you guys can help me out here.

UPDATE enter image description here

*UPDATE** Okay, now things are getting crazy. When i do this

export const products: ({ id: number;description: string;image: string;price: number;type: Object } |
{ id: number;name: string;description: string;image: string;price: number;type: Object })[] = [
{
    id: 1,
    description: "Description of product 1",
    image: "https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8",
    price: 15.15,
    type: productType
},
{
    id: 2,
    name: "Product 2",
    description: "Description of product 2",
    image: "https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8",
    price: 15.15,
    type: productType
},
{
    id: 3,
    name: "Product 3",
    description: "Description of product 3",
    image: "https://www.google.nl/imgres?imgurl=https%3A%2F%2Fangular.io%2Fresources%2Fimages%2Flogos%2Fangular2%2Fangular.svg&imgrefurl=https%3A%2F%2Fangular.io%2F&docid=bJoyJcb-C12SHM&tbnid=G_BYSyR7DGpqqM%3A&vet=1&w=800&h=800&bih=1060&biw=1060&q=angular2&ved=0ahUKEwjdrq6it87RAhUEExoKHdXlAYIQMwgcKAAwAA&iact=mrc&uact=8",
    price: 15.15,
    type: productType2
}

It gives no errors, but does not show the name.

1
  • Not sure if I understand what you mean. So I have to use constructor in my models or change them to an interface? Or should I use a constructor in my mock? Commented Jan 20, 2017 at 14:11

1 Answer 1

4

Actually tested your code, there only seems to be async problem. Try using the safe operator: ? (otherwise also called elvis-operator) like so:

<h1>{{product?.name}}</h1>

The other option is to use *ngIf like so:

<h1 *ngIf="product">{{product.name}}</h1>

More about the elvis-operator here. This comes really handy in Angular (2) apps, since we are constantly dealing with async operations, since (usually) the view is rendered before data is received.

If you prefer *ngIf this also works, app won't throw error since the code you have wrapped inside it, is only rendered when there is data present, in this case in your product object.

Working Plunker

You could change your classes to interfaces instead, so:

export interface Product  {
    id: number;
    name: string;
    description: string;
    image: string;
    price: number;
    type: ProductType;
}

or add constructor to your classes:

export class Product  {
    constructor(
      public id: number,
      public name: string,
      public description: string,
      public image: string,
      public price: number,
      public type: ProductType
    ) { }
}
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you very much, Elvis did help me. But the second error is stil showing up. TypeError: Cannot read property 'description' of undefined and error TS2322: Type '{ ... }' is not assignable to type 'Product[]'.Type ...
Okay, well where are you trying to use description, doesn't show in the code you provided?
I cannot reproduce your issue, updated my answer with a working plunker with the code you have provided, please refer to that :)
Please see my update. I get the same results, but whit that error
Try changing to Interface instead (look updated answer). I don't know really what to do more, the code you have provided works as should. You would have to reproduce your issue in a plunker, since with the code you have given the issue cannot be reproduced.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.