2
votes

I'm following Angular tutorial to build a simple app. The app sends ajax to search users when I type terms in the input box. I'm confused with the Observable here.

(1) I want to clear the data if the search term is shorter than 3 words. I use Observable.of to return an empty array.

(2) An empty array also will be returned in catch block if a http error occurs.

However after one of these two cases, it seems the stream 'stops' because I point this.users to a new Observable. Should I do something like this.users = new Subject() again? What's the correct way to do it here?

html:

<div class="wrapper">
    <input #searchBox id="search-box" (keyup)="search(searchBox.value)" />
    <div class="loader" [hidden]="!loading"></div>
</div>

getUserService:

//Sending ajax, return an Observable

component:

export class searchComponent implements OnInit {

  constructor(private getUserService: GetUserService) { }

    private searchTerms = new Subject<string>();

    users: Observable<User[]>;
    loading: boolean = false;

    search(term: string): void {
        if(term.length >= 3) {
            this.loading = true;
            this.searchTerms.next(term);
        } else {

            //issue (1) occurs after this

            this.users = Observable.of<User[]>([]);
        }
  }

  ngOnInit(): void {
    this.users = this.searchTerms
      .debounceTime(400)
      .distinctUntilChanged()
      //service will not be called after (1) or (2) occurs
      .switchMap(term => this.getUserService.getUser(term))
            .map(data => {
                this.loading = false;
                return data;
            })
      .catch(error => {

        //issue (2) occurs after this

        this.loading = false;
        return Observable.of<User[]>([]);
      });
  }
}
1

1 Answers

3
votes

You're not doing things in the right place. It should rather be

search(term: string) {
    // emit systematically. The observable chain will just return
    // 0 result if the term is too short
    this.searchTerms.next(term);
}

ngOnInit() {
  this.users = this.searchTerms
      .debounceTime(400)
      .distinctUntilChanged()
      .switchMap(term => {
        if (term.length < 3) {
          return Observable.of([]);
        }
        else {
          this.loading = true;
          return this.getUserService.getUser(term)
                     // catch here to make sure that an http error doesn't break the chain
                     .catch(() => return Observable.of([])
                     .finally(() => this.loading = false);
        }
      });
}