1
  • searchFunction is being called when a user enters value in autocomplete textbox. So, what this code should do is return the oprions to the autocomplete dropdown on the basis of user input and it should only show the options of the last query.

  • If I use this code and when it called in other place is does not return anything(when I use subject and observable like above). The place where this function is called expect a observable, so we have to return and observable from here. Also, I cannot edit/chnage the function which is calling the above function.

  • To get only the last results I need switchMap. Is there anyother way to do same?

  • Below code is not working. Pleas suggest want needs to be changed

export class AppComponent {
  readonly search = new ReplaySubject<string>(1);
  searchResponse!: Observable<string[]>;

  constructor(private http: HttpClient) {}

  searchFunction = (query: string) => {
    return (this.searchResponse = this.search.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap((query: string) => {
        return this.http.searchData(query).pipe(
          map((res: string[]) => {
            return res.slice(0, 100);
          })
        );
      })
    ));
  };
}
Svibhor
  • 53
  • 10

2 Answers2

2

The problem is with this:

searchFunction is being called when a user enters value in autocomplete textbox

You create a new subcription each time you call the function. While the template should unsubscribe from the previous subscription, the solution is not ideal.

I would try something like this:

export class AppComponent {
  readonly search = new Subject<string>();
  readonly searchResponse: Observable<string[]>;

  constructor(private http: HttpClient) {
    this.searchResponse = this.search.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap((query: string) => {
        return this.http.searchData(query).pipe(
          map((res: string[]) => {
            return res.slice(0, 100);
          }),
          // So we don't wreck the pipe. Import EMPTY from 'rxjs'
          catchError(() => EMPTY)
        );
      })
  }

  searchFunction = (query: string) => {
    this.search.next(query);
  };
}

In that case you have single subscription to the search term. If you're using reactive forms you could listen to valueChanges.

kvetis
  • 6,682
  • 1
  • 28
  • 48
  • I used your code, it is working but I have to return this.searchResponse from inside searchFunction and it will be subscribed somewhere else. I am able to see on the last result on UI but the browser does not cancel the previous api. Can this also be fixed ? – Svibhor Feb 18 '21 at 09:58
  • That's the same mistake again. Do not subscribe to the solution anywhere else than the template. – kvetis Feb 18 '21 at 10:26
  • If you do need the data somewhere else than a single field on FE, expand the question and I can adjust the answer accordingly. – kvetis Feb 18 '21 at 10:27
  • 1
    Thank you for your help, it is working now. – Svibhor Feb 18 '21 at 10:30
0

In this article you can find a complete implementation with RxJS operators - see section "Search TypeAhead - switchMap Operator Example" - hope it helps!

https://blog.angular-university.io/rxjs-higher-order-mapping/

Dani P.
  • 1,073
  • 1
  • 10
  • 28