Search code examples
angularbehaviorsubject

behaviorSubject return only when there is something new


I have the following problem, when I call the getStudentsList function, it goes to the server to find the new values that I need, but the behaviorSubject returns the current value again (This causes me problems because it load the view with the previous values) while I wait for the server information to return. How can I do to avoid this behavior?

  getStudentsList(params): Observable<StudentsListGrid> {
    if (this.studentListSubject$ === undefined) {
      this.studentListSubject$ = new BehaviorSubject<StudentListGrid>(null);
    }
    this.refetchStudentList(params);
    return this.studentListSubject$.asObservable().pipe(filter((value) => value !== null));
  }

  refetchStudentList(gridParams) {
    const subscription = this.http.post<StudentListGrid>(this.baseUrl + 'GetStudents', {gridParams} ,httpOptions).pipe(map(data => this.setDefaultValuesToStudent(data))).subscribe(
      (response) => {

        this.studentListSubject$.next(response);
        subscription.unsubscribe();
      });
  }

Solution

  • Based on the definition of BehaviorSubject from doc

    BehaviorSubject: A variant of Subject that requires an initial value and emits its current value whenever it is subscribed to

    Solution 1

    For a quick solution, you can set null before you return Observable in the getStudentsList function:

      getStudentsList(params): Observable<StudentsListGrid> {
        if (this.studentListSubject$ === undefined) {
          this.studentListSubject$ = new BehaviorSubject<StudentListGrid>(null);
        }
        this.refetchStudentList(params);
        // add this line
        this.studentListSubject$.next(null);
        return this.studentListSubject$.asObservable().pipe(filter((value) => value !== null));
      }
    

    The reason is you empty the last value of BehaviorSubject by passing null so the return of this function always returns a fresh value.

    Solution 2

    Another way (better way) is to use distinctUntilChanged from RxJs library, I suppose your name become different in each response:

     getStudentsList(params): Observable<StudentsListGrid> {
        if (this.studentListSubject$ === undefined) {
          this.studentListSubject$ = new BehaviorSubject<StudentListGrid>(null);
        }
        this.refetchStudentList(params);
        return this.studentListSubject$.asObservable().pipe(
                 filter((value) => value !== null),
                 distinctUntilChanged((prev, curr) => prev.name === curr.name));
      }
    

    I hope this answer helps you.