Ngx-bootstrap: Typeahead async results don't show since 5.5.0 (because of re-filtering)

Created on 29 Jan 2020  Â·  12Comments  Â·  Source: valor-software/ngx-bootstrap

Hello,

Since yesterday (release 5.5.0), typeahead async suggestions don't show up anymore. With version 5.4.0, everything works fine. I highly suspect commit 8378105 / PR #3728.

Angular version: 8.2.11
Bootstrap version: 3.4.1

Plunker/StackBlitz that reproduces the issue: I spent 20 minutes trying to make one, but the Plunker fails with (SystemJS) XHR error (404) loading https://unpkg.com/rxjs/operators.js, and I can't use StackBlitz for 5+ minutes without it crashing. But the bug is easy to describe:

<input [(ngModel)]='searchText' [typeahead]='suggestions$' />
import {Component} from '@angular/core';
import {Observable, Observer, from} from 'rxjs';
import {switchMap} from 'rxjs/operators';

export class AppComponent  {
  searchText: string = '';
  suggestions$!: Observable<string[]>;

  ngOnInit() {
    this.suggestions$ = Observable.create((observer: Observer<string>) => {
      observer.next(this.searchText);
    })
    .pipe(switchMap((query: string) =>
      from(new Promise(r => setTimeout(() => r(['1', '2']), 500)))
    ));
  }
}

Expected behavior (works with 5.4.0): typeahead suggestions [1, 2] are shown.
Actual behavior with 5.5.0: suggestions are not shown.

comp(typeahead) issue

Most helpful comment

@KelseySheely @adrienverge Thanks for your comments! I agree with you. I'm going to roll this change back. And I'm planning to find out another way to filter data via ngx-bootstrap, so developers could filter data via our or their functionality.

All 12 comments

@adrienverge Hi! First of all in your code above you missed typeaheadAsync property. It has to be:

<input [(ngModel)]='searchText' [typeahead]='suggestions$' [typeaheadAsync]="true">

Also, This code is enough to create Observable:

this.suggestions$ = from(new Promise(r => setTimeout(() => r(['1', '2']), 500)));

Could you check my StackBlitz example, please?

Hey Irina, thanks for your fast answer! I already tried typeaheadAsync, but it didn't change anything so I did not include it in the example (to simplify).

The problem is that since 5.5.0, it's not possible to do the search/filtering ourselves, like it was possible before (from version 1 to 5.4.0).

Said differently, this code example (that was copied-pasted from a previous doc version, probably in 2016) doesn't work anymore with 5.5.0 because ngx-bootstrap re-filters items after we've already filtered them:

this.suggestions$ = Observable.create((observer: Observer<string>) => {
  // Runs on every search:
  observer.next(this.searchText);
})
.pipe(switchMap((query: string) =>
  from(
    // Returns already-filtered results from an optimized search:
    this.myService.searchItems(query, 'ascending', 20)
    // ↑
    //  all these should be displayed, they shouldn't be re-filtered by ngx-bootstrap
  )
));

I hope this is clear, please let me know what you think.

@adrienverge okay, let me check

@adrienverge if I understand you correctly, your initial data is an empty array and you send request to get data from your server on every search. Correctly? I've checked such case and it works as expected. Could you please give me more information?

@IraErshova thanks for following this up. Yes, you perfectly describe our use-case!

To show the problem, I adapted your last StackBlitz (that fetched a list from https://gorest.co.in/...?first_name=xyz), so that results don't always contain the searched string. For example, searching "Nicolette Boyle" finds 1 result, but returns an object like {id: 123, phone: "+7123456"}.

In that case, it seems that ngx-bootstrap 5.5.0 re-filters results, which was not the case with 5.4.0. Since these results don't contain the initial string, none are kept.

Please see https://stackblitz.com/edit/angular-8t8dcm-puwywo:

  • with 5.4.0, searching col finds 10 results, and displays them all,
  • with 5.5.0, searching col finds 10 results, but doesn't display any.

@adrienverge Thanks for your clarification! I can see that if you enter Nicolette it returns suggestion with id and phone according to your changes. But if you enter Nicolette Boyle it doesn't return anything because of search by first_name only.

The reason why it doesn't return anything could be in your code, which processes the result of the request. Are you able to debug asyncActions method of typeahead.directive.ts with your code? Because I can't understand in what cases this issue could happen. And until we find out you can use 5.4.X

I think there is a miscommunication here. It doesn't matter if you put in Nicolette Boyle or just Nicolette. In either case, no data displays.

You can very clearly see the issue in action if you update the stack blitz to 5.5.0 and type in Nicolette. It will show 2 Matching items, but the dropdown will not show up at all.

Note, I took out the typeaheadOptionField="first_name" from the template, but the results are the same either way.

Here's the forked Stack Blitz:

https://stackblitz.com/edit/angular-8t8dcm-kzbw52

Note that if you include typeaheadOptionField="first_name" and you include the first_name with the mapped object, it will work. However, this does not help if the whole point of the search is to do a more comprehensive search through an API, rather than being limited to a single field.

In my case, I would like to do a client search which searches first name, last name, city, etc. on the back end, as well as a concatenated first and last name. I would rather not have to create a whole new field to store all of the data that I want to search through, essentially duplicating the code that I already wrote on the back end. Is there a way to stop it from filtering after the data comes back from the Observable?

Looks like this was broken according to the following Bug Report, but there was no discussion before implementing this breaking change.

https://github.com/valor-software/ngx-bootstrap/issues/3725

IMO, if the user wants to filter it themselves, they should have the last word. It should absolutely not be run through the ngx filter after the user has filtered it according to what they want. Can you please roll this back or create a new directive to stop it from re-filtering.

@IraErshova thanks for your reply, sorry for my late answer!

My StackBlitz example had ngx-bootstrap 5.4.0, to show that it did work before 5.5.0.
But if you try with the new version, typing "Nicolette" shows "Matching items: 2" but doesn't show any typeahead suggestion.
(Thanks @KelseySheely for the updated StackBlitz with 5.5.0.)

IMO, if the user wants to filter it themselves, they should have the last word.

I agree with @KelseySheely. It was possible from version 1 (2016) to version 5.4.0, and makes sense to be able to filter results on something more complex than just text in one of the fields.
Example: if searching "Nicolette Boyle" returns an object like {id: 123, phone: "+7123456"} (which doesn't contain the searched string), there is no way to display this typeahead suggestion with 5.5.0.

@KelseySheely @adrienverge Thanks for your comments! I agree with you. I'm going to roll this change back. And I'm planning to find out another way to filter data via ngx-bootstrap, so developers could filter data via our or their functionality.

@IraErshova do you please have any estimate on when this revert will be released? Latest released version is 5.5.0 (28 Jan). We're suffering from the broken filtering too.

Thanks for reporting this error, I too hit upon it today after a lot of head scratching. I have needed to roll back to 5.4.0 until the next release.

Was this page helpful?
0 / 5 - 0 ratings