0
votes

I'm still learning on RxJS using Angular and I want to solve a basic scenario with the correct approach. I have a component that render a list, so when it loads, in the ngOnInit event, I'm calling the service that consumes the API (the result is an Array with only 20 items, just to show something, but in the database I have probably 1500 records). The problem I currently have is: the component also have a search bar that consume the same API but sends a searchTerm to filter the items based on it. Since the search event is going to be executed only when the user type something in the search bar, if I remove the call in the ngOnInit, when the page loads, I'll have an empty screen, but if I add that call, when I search the event is not executed. I know that is because I'm using the exercises$ property in both places, but I don't know how to solve that. My question is, how can I use the same Observable for both process? or, what is the best approach to accomplish this? Thank you in advance.

This is my code in the component.

Component properties

exercises$: Observable<ExerciseModel[]>;
searchTerm = new FormControl();
searchTerms$: Observable<string> = this.searchTerm.valueChanges;
exercises$ = this.searchTerms$.pipe(
    tap(() => this.errorMsg = ''),
    debounceTime(1000),
    distinctUntilChanged(),
    switchMap(searchTerm => this._exerciseSrv.getExercisesBySearch({ name: searchTerm })
      .pipe(
        catchError(err => {
          this.errorMsg = err;
          return EMPTY;
        })
      )
    ),
    map((data) => data)
  );

ngOnInit

this.exercises$ = this._exerciseSrv.getExercisesBySearch({name: null}).pipe(
      catchError(errorMessage => {
        this.errorMsg = errorMessage;
        return []
      })
    );

Component HTML

<div *ngFor="let item of exercises$ | async"></div>
2

2 Answers

2
votes

Try to initialize the observable using startWith:

exercises$ = this.searchTerms$.pipe(
    startWith(null),
    tap(() => this.errorMsg = ''),
    debounceTime(1000),
    distinctUntilChanged(),
    switchMap(searchTerm => this._exerciseSrv.getExercisesBySearch({ name: searchTerm })
      .pipe(
        catchError(err => {
          this.errorMsg = err;
          return EMPTY;
        })
      )
    ),
    map((data) => data)
  );

and remove the assignment from ngOnInit.

0
votes

Can you assign your exercise$ value in subscribe part.

Component Properties:

exercises: ExerciseModel[];
searchTerm = new FormControl();
searchTerms$: Observable<string> = this.searchTerm.valueChanges;

ngOnInit:

// get records
this._exerciseSrv.getExercisesBySearch({name: null}).pipe(catchError(errorMessage => {
        this.errorMsg = errorMessage;
        return []
      })). subscribe((data) => this.exercise = data );

// get records base on searchTerms
this.searchTerms$.pipe(tap(() => this.errorMsg = ''),
        debounceTime(1000),
        distinctUntilChanged(),
        switchMap(searchTerm => this._exerciseSrv.getExercisesBySearch({ name: searchTerm })
          .pipe(catchError(err => {
              this.errorMsg = err;
              return EMPTY;
            })
        )
     ), map((data) => data)
).subscribe((data) => this.exercise = data);

Component HTML:

<div *ngFor="let item of exercises$ | async"></div>