1

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?

1
  • Try replacing your 'filter()' call with 'map()' and output the result to the console. Each truthy value should correspond to an item at the same index that will be returned by filter(). This will show you what is going on. Commented Apr 24, 2024 at 13:52

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

BTW, instead of .indexOf(x) !== -1, you can do simply .includes(x).
0

You can not use a return inside a loop forEach -the function is going executing.

So, if you want you should use some like

  return values.filter((value: User) => {
      let find=false; //at fisrt not found
      filters.forEach(f => {
          const userNameFound = value.name.toLowerCase().indexOf(f.toLowerCase()) !== -1;
          const userSurnameFound = value.surname.toLowerCase().indexOf(f.toLowerCase()) !== -1;
          const ageFound = value.age.toLowerCase().indexOf(f.toLowerCase()) !== -1;

          //if with a filter we put the value to true
          if (userNameFound || userSurnameFound || ageFound) {
              find= true;
          }
      });
      return find;
    });
  }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.