Filter Fridays

Performance is a huge aspect of Angular 2.  It seems that one of the main complaints about version 1 was the performance.  While performance is important, it’s also important to remember that this team created a framework that has to constantly check your app, monitoring for changes, in order to maintain bindings and data properly.  I compare it to adding a function to the onscroll event – it’s going to fire on every single pixel scroll of a user’s screen.  Not efficient at all, but sometimes necessary for the effect/functionality you want.

So some overhead is to be expected- but with version 2, they did seem to take into account the criticisms of 1’s performance.  One result- they removed the built in sort/filter pipes from ngFor.  While those pipes were very useful, they also caused some performance issues (as well as adding to the size of the framework- another complaint being addressed in version 2).

The upshot is, if you want to sort or filter you list items, you have to create a service for it yourself.  Which was actually pretty fun.

First up: search/filter.  It seemed to work well as a service instead of a pipe, so that’s the direction we took.  The input field is just a simple text input with a binding to an ngFormControl element.  By using this built in element, we can hijack the Observable that comes with it for some cool shortcuts.

So, as a user types, the list is filtered according to the key they press.  Done in a service, we set up a function to take the item (the string being searched for), group (the greater json array being searched through), and an optional property (allowing search by name or by email).  That function returns a promise- this promise uses the array.filter function that loops over each letter to check for a match.  First, though, we convert everything to lowercase (seemed like a case insensitive search would be best):

return new Promise(
    function (resolve, reject) {
        var filtered = group.filter((g) => {
        var lowerItem = item.toLowerCase();
        var lowerProp = g[property].toLowerCase();

        if (lowerProp.search(lowerItem) !== -1) return g[property];
    });
    resolve(filtered);
});

It would also work to regex search the string, but this seemed easier for now (than creating a regex with a variable input).  This gets passed back to that ngFormControl aspect.  We can use the valueChanges built in check- this will give us an Observable to subscribe to.  We can then pass that subscription on to the filter service function, and we are checking on each keystroke.  If there’s a match, the list is filtered.  If not, no results show (until the input is cleared, then all listings are back).

this.term.valueChanges
  .debounceTime(400)
  .subscribe(term => this._searchService.findItems(term, this.originalContacts, this.filterParam)
  .then((filteredContacts) => {
    if (term.length > 0) {
      this.contacts = filteredContacts;
    } else {
      this.contacts = this.originalContacts;
    }
}));

There’s one more aspect that I thought was really cool.  In the original example of bad performance sometimes being necessary, I used the onscroll event.  But there’s a way to mitigate that performance hit: a debounce function.  Essentially, this puts a delay on a function, so instead of firing on every single pixel scroll, it will fire, then ‘sleep’ for a set amount of scroll lines, then fire again.  This prevents unnecessary function calls.

Angular 2 Observables (like valueChanges on the form module) come with a built in debounce option (that’s the debounceTime chained in the above code).  Just pop it on and give it the number of milliseconds to wait before firing again.  So, this function will wait 400ms after the user stops typing before actually firing.

Super useful stuff- thanks Angular team!  Next week: the orderBy pipe reborn as a service!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s