How to iterate in a union type array in angular template
Asked Answered
M

4

8

I am new to angular and started working on version 12 and I am stuck in a point. Where I want to iterate in my union array in the template but it gives me error.

Error: Type 'IBasketItem[] | IOrderItem[]' is not assignable to type 'NgIterable'.

this is my union array in the component on which I want to iterate.

@Input() items: IBasketItem[] | IOrderItem[] = [];

this is the template code

<tr *ngFor="let item of items" class="border-0">

it gives me a red line under the ' of ' keyword with above mentioned error

here is the IBasketItem interface

export interface IBasketItem {
id: number;
productName: string;
price: number;
quantity: number;
pictureUrl: string;
brand: string;
type: string;

}

and this is the IOrderItem interface

export interface IOrderItem {
productId: number;
productName: string;
pictureUrl: string;
price: number;
quantity: number;

}

I will be thankful if someone suggest a solution.

Meatball answered 17/8, 2021 at 18:1 Comment(0)
S
1

Declare array of type like this @Input() items: [IBasketItem | IOrderItem] = [];

This is iterable then.

OR this way

@Input() items: Array<IBasketItem | IOrderItem> = [];

Suzansuzann answered 17/8, 2021 at 18:7 Comment(2)
thank for your time but your solution are not working for me. when I applied your solutions it unable to find properties in my interfaces.Meatball
@Fahad look at my answer. In special remark 1Hutchens
H
1

while @Hitech answer might work, what you are trying to do is a bit sketchy. You will have to check if you have the 'brand' or 'type' property available and then display them or have different logic for an orderItem or for a basketItem.

I recommend you have a common interface for both of them and then iterate through that array:

export interface IItem {
    id: number;
    productName: string;
    price: number;
    quantity: number;
    pictureUrl: string;
}

export interface IOrderItem extends IItem {
    productId: number; // might be the same with the id from the base class, depending on your logic
}

export interface IBasketItem extends IItem {
    brand: string;
    type: string;
}

@Input() items: IItem[] = [];

or have two separate arrays for this and have a for loop for each of them.

@Input() basketItems: IBasketItem [] = [];
@Input() odredItems: IOrderItem [] = [];
Happenstance answered 17/8, 2021 at 18:40 Comment(1)
@qbBlaze thanks for your such effort but sadly your 1st solution is not working for me and for 2nd solution, I cannot use separate arrays.Meatball
H
1

This is an interesting error. My intern got the same error and understanding the error message, I see the problem.

@Input() items: IBasketItem[] | IOrderItem[] = [];

When you declare a union that the types can be 2 different arrays you don't have an array iterator for both arrays, in fact, you have one for each possible array. That's why the compiler throws an error, it doesn´t know which iterator to use.

@Input() items: (IBasketItem | IOrderItem)[] = [];

So, to solve the problem you need to assure that you have just one iterator, a list of union type. This solution solves our same problem.

Few remarks about this solution:

  1. As you are handling a union type, you only can access directly properties that have an intersection in the Union, or you should use a type guard and handle each union type.
  2. (IBasketItem | IOrderItem)[] allows you to have an array with mixed types, and if you do that, the compiler won´t throw an error. But in general, you are always receiving as input one type array. This shouldn't be a problem :)
Hutchens answered 9/12, 2022 at 2:23 Comment(0)
P
0

Angular checks the expressions and bindings within the templates in the application code. Try setting "strictTemplates": false in tsconfig.json file and you should be fine.

Ph answered 3/2, 2022 at 4:3 Comment(1)
Watchout setting it to false, because it is a really useful configSidnee

© 2022 - 2024 — McMap. All rights reserved.