angulartypescriptangular-pipeangular17

Angular 17 - Showing empty data when using pipe


I'm using Angular 17 with the following code:

database.component.html

@for(user of (users | userPipe:filters); track user.id) {
    <tr id="{{ user.id }}">
        <td>{{ user.name }}</td>
        <td>{{ user.surname }}</td>
        <td>{{ user.age }}</td>
    </tr>
}
@empty {
    <tr>
        <td colspan="3">Empty</td>
    </tr>
}

filters is a string array with the keywords for filtering the matched database entries.

database.pipe.ts

@Pipe({
    name: 'userPipe',
    pure: false
})
export class databasePipe implements PipeTransform {
    transform(values: Users[], filters: string[]): Users[] {
        
        if (!filters || filters.length === 0 || values.length === 0) {
            return values;
        }

        return values.filter((value: User) => {
            filters.forEach(filter => {
                const userNameFound = value.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1;
                const userSurnameFound = value.surname.toLowerCase().indexOf(filter.toLowerCase()) !== -1;
                const ageFound = value.age.toLowerCase().indexOf(filter.toLowerCase()) !== -1;

                if (userNameFound || userSurnameFound || ageFound) {
                
                    console.log("value: ", value);
                    return value;
                }
                return "";
            });
        });
    }
}

It is working and I can see matching entries with value: <value> in the browser console just fine but my filtered table just returns "Empty" and no data is shown.

Does anyone know why this happens?


Solution

  • Your filter logic in databasePipe is incorrect. You are not returning the boolean value (predicate) to indicate that the element is selected, but return undefined (falsy value). Thus, your table will show the @empty template.

    Instead, you should use .some() so that it returns true when fulfilling any filter.

    return values.filter((value: User) => {
      return filters.some((filter) => {
        const userNameFound =
          value.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1;
        const userSurnameFound =
          value.surname.toLowerCase().indexOf(filter.toLowerCase()) !== -1;
        const ageFound =
          value.age.toLowerCase().indexOf(filter.toLowerCase()) !== -1;
    
        return userNameFound || userSurnameFound || ageFound;
      });
    });
    

    Demo @ StackBlitz