Jeremy
Jeremy

Reputation: 3548

Is there a way to declare a specific type in ngFor?

I am using ngFor to iterate a collection of a specific type [Menu] in Angular 4.x.

Then looping on a collection property of the menu object (menu.items).

Unfortunately, the property is unknown in my IDE (Eclipse + Angular IDE), even though the Menu class defines the items property as an array of MenuItem.

Is there a solution?

Red squiggles

Relevant class declarations -

export class MenuBase {
  id: string;
  title: string;
  isPublic: boolean;
  roles: string[];
  items: MenuItem[];
  position: number;
// rest of class omitted
}

export class MenuItem extends MenuBase {
  menuItemType: MenuItemType;
  callback: () => void;
  location: string;

  constructor (options: any) {
    super(options);
    this.location = options.location;
    this.menuItemType = options.menuItemType || MenuItemType.location;
    this.callback = options.callback;
  }
}

export class Menu extends MenuBase {
  constructor (options: any) {
    super(options);
  }
}

Additional information

This is the project I was working on: https://github.com/savantly-net/ngx-menu. The project will show an error in Eclipse, even though it's valid.

I never created any documentation, but I used it here - https://github.com/savantly-net/sprout-platform/tree/master/web/sprout-web-ui

Upvotes: 20

Views: 15217

Answers (3)

Carsten Luxig
Carsten Luxig

Reputation: 149

BTW: In Visual Studio Code, you need to specify it within the appropriate tsconfig.json file:

"angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "strictInputTypes": true,
}

Upvotes: 2

danday74
danday74

Reputation: 56936

You can use a pipe to work around this. This code was throwing a type error:

<ng-container *ngIf="(item.value.value - defaultCssFilters[item.key].value) > 0">
  ...
</ng-container>

To fix it I used a pipe:

<ng-container *ngIf="(item.value.value - (defaultCssFilters | filterValue: item.key)) > 0">
  ...
</ng-container>

The pipe looks like this:

@Pipe({ name: 'filterValue' })
export class FilterValuePipe implements PipeTransform {
  transform(cssFilters: ICssFilters, key: TCssFilter): number {
    return cssFilters[key].value;
  }
}

This works because in the pipe you can declare your types.

When working with existing code, this is far less cumbersome than creating a new component.

Upvotes: 1

C.OG
C.OG

Reputation: 6529

What I've had success with is creating a new component for the template that the *ngFor will render and have that typed.

Container template:

<ng-container *ngFor="item of items" >
  <my-custom-component [item]="item"></my-custom-component>
</ng-container>

Custom Component template:

<div *ngIf="item.menuItemType == 'dropdown'">
  <!-- -->
</div>

ts file:

@Component({})
export class MyCustomComponent {
  @Input() item: MenuItem
}

Upvotes: 12

Related Questions