4

I am using the clarity datagrid and I want to be able to filter based on a search filter the entire grid content.

I tried to create a pipe. The pipe is included inside the app.module. The pipe is called the first time the component is loaded (and nothing is supposed to happen), but for some reason, when I put something into my , nothing is happening. No call to the 'userFilter' pipe.

user.component.html

<input type="text" id="search" placeholder="Search..." ([ngModel])="searchTerm">
...
<clr-dg-row *clrDgItems="let user of users | userFilter: searchTerm" [clrDgItem]="user" (click)="backupSelectedUser(user)">
  <clr-dg-cell>{{ user.username }}</clr-dg-cell>
  <clr-dg-cell>{{ user.name }}</clr-dg-cell>
  <clr-dg-cell>{{ user.firstName }}</clr-dg-cell>
</clr-dg-row>
...

search.pipe.ts

transform(items: any, term: any): any {
  if (term === undefined) {
    return items;
  }

  return items.filter(function (item) {
    for (const property in item) {
      if (item[property] === null) {
        continue;
      }
      if (item[property].toString().toLowerCase().includes(term.toLowerCase())) {
        return true;
      }
    }
    return false;
  });
}

UPDATE: I did a little typo for the ngModel. It should be [(ngModel)] instead!

David
  • 1,241
  • 20
  • 36
  • I have a feeling that this is because when you use `clrDgItems`, all the paging, sorting and searching is done by Clarity. Does it get called multiple times if you change it to a regular `ngFor`? Also, are you sure your `users` variable is immutable? If it is not, the pipe may be ignoring any changes to the array – Ruan Mendes Dec 11 '17 at 16:19
  • It was not called at all, but the reason was because I did a little typo with my ngModel. It should be [(ngModel)] instead! Shame on me. It is working – David Dec 11 '17 at 21:39

1 Answers1

2

I remember writing a plunker showing exactly this a few months back: https://plnkr.co/edit/59FZKya2Soa7Ofnlge3B?p=preview

Based on what you described, this is exactly what you want. You should not use pipes like you are doing now in iterators, because it forces Angular to recompute them for every change detection, which is way too heavy. So the recommended solution is to stick with *clrDgItems="let user of users", and set the users property itself to the filtered-down array, so that you only recompute the filter result when the user types something.

Eudes
  • 1,521
  • 9
  • 17
  • Worked perfectly, but now I would like to know why the get search() get called 27 times (in my case) when the component loads? – David Dec 11 '17 at 21:21
  • Hi @Eudes, quick one for you. Any idea why your and the datagrid filter input have the X at the end of the line when writing characters? Mine does not have it. Is it because I am running within Electron? – David Dec 11 '17 at 23:42
  • Yes, the "x" to empty an input is a browser-specific feature. For instance, I'm on Mac using Chrome and I don't have it. – Eudes Dec 12 '17 at 13:40
  • 1
    Regarding the 27 calls to the getter, that's your application triggering change detection 27 times when starting. They are triggered every time an AJAX request comes back, whenever a timeout or interval ticks, whenever an event listener is called (like "click" or "mousemove"), ... One catch-all solution is to use `ChangeDetectionStrategy.OnPush`, but you might just be hiding actual issues by doing this. – Eudes Dec 12 '17 at 13:43
  • Finally, I changed my search strategy. I used the technique described in Josh Morony's blog. Working fine too and seems it is the way to go too. https://www.joshmorony.com/high-performance-list-filtering-in-ionic-2/ – David Dec 13 '17 at 17:36