1

In my Angular 2 app I am wondering if there's a way I can iterate over an array while also filtering on a certain property in the *ngFor block. So the syntax would look something like this:

<ng-template *ngFor="let flag['completed === false'] of service.flags">
    <span class="standard-flag" 
        [class.hold-flag]="flag?.flagType === 'hold'">Flag
    </span>
</ng-template>

So basically the logic is, for each object ("flag" is an object) in the array that exists, where the "completed" property is set to "false", return that value. Rather than first iterating over the array, and then using *ngIf to filter further, it'd be nice (and very helpful in my particular situation) if I could do both in the *ngFor block. Possible?

The reason why I'm interested in this kind of construction specifically is because I want to return only the first of the values where "completed" is "false", and I could handle that with "let i = index" in the *ngFor block in that case. But I don't want to return the first of ALL flag objects, just the flag objects where the "completed" property is set to "false".

Lazar Ljubenović
  • 18,976
  • 10
  • 56
  • 91
Muirik
  • 6,049
  • 7
  • 58
  • 116
  • 2
    You can implement PipeTransform and use it in the ng-if as a filter https://angular.io/guide/pipes – Janier Aug 01 '17 at 16:47
  • 1
    Make use of Pipes here as pointed out by @Jocket check out this link for a similar implementaion here the input is from the user [link](https://plnkr.co/edit/Bxfw6a?p=info). for more info on pipes check this [link](https://rahulrsingh09.github.io/AngularConcepts/pipes) – Rahul Singh Aug 01 '17 at 16:49
  • Thanks, this may very well do the trick. – Muirik Aug 01 '17 at 16:52

2 Answers2

5

It's not a good idea to use a pipe for filtering. See the link here: https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

Rather, add code in your component to perform your filtering. Then use your ngFor over the filtered data.

Below is an example. Then you would just use ngFor over the filteredProducts in this example.

import { Component, OnInit } from '@angular/core';

import { IProduct } from './product';
import { ProductService } from './product.service';

@Component({
    templateUrl: './product-list.component.html'
})
export class ProductListComponent implements OnInit {

    _listFilter: string;
    get listFilter(): string {
        return this._listFilter;
    }
    set listFilter(value: string) {
        this._listFilter = value;
        this.filteredProducts = this.listFilter ? this.performFilter(this.listFilter) : this.products;
    }

    filteredProducts: IProduct[];
    products: IProduct[] = [];

    constructor(private _productService: ProductService) {

    }

    performFilter(filterBy: string): IProduct[] {
        filterBy = filterBy.toLocaleLowerCase();
        return this.products.filter((product: IProduct) =>
              product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
    }

    ngOnInit(): void {
        this._productService.getProducts()
                .subscribe(products => {
                    this.products = products;
                    this.filteredProducts = this.products;
                },
                    error => this.errorMessage = <any>error);
    }
}
DeborahK
  • 57,520
  • 12
  • 104
  • 129
2

You can create a custom pipe to filter the items when u loop over an for loop.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'notCompleted'})
export class notCompletedPipe implements PipeTransform {
  transform(value: string]): string {
    return value != 'completed';
  }
}

and Use it in HTML like this,

<ng-template *ngFor="let flag['completed === false'] of service.flags | notCompleted">
    <span class="standard-flag" 
        [class.hold-flag]="flag?.flagType === 'hold'">Flag
    </span>
</ng-template>
Saravanan I
  • 1,229
  • 6
  • 9