Search code examples
angularrxjsngrx

How to refactor nested subscription in angular


I have an angular13 app with rxjs7.5.0

I need to get list of students based on class code. Here is how I addressed this requirement.

export class StudentsComponent implements OnInit {
students: Student[] = [];
private appNum: string;
private sectionCode: string;

constructor(
 private route: ActivatedRoute,
 private studentSvc: StudentService
) {}

ngOnInit(): void {
 this.route.queryParamMap.subscribe((params) => {
  let classCode = params.get('cc') ?? '';

  classCode = decodeURIComponent(classCode);
  if (classCode.match(ALPHABETS_REGEX)) {
    this.studentSvc
      .fetchStudents({
        sec: sectionCode,
      })
      .subscribe((response) => {
        if (response.status == HttpStatusCode.Ok) {
          this.students = response.data(obj);
        }
      });
  }

This is functioning as per app requirements. However, I see this would end up in callback & hell chain & is an anti-pattern

Based on the links

Which operator & how can I get rid of this anti-pattern ?

Thanks!


Solution

  • What you can do is something along these lines (see inline comments for explanation)

    // you start from the this.route.queryParamMap and you transform it
    // using a chain of pipeable operators
    this.route.queryParamMap.pipe(
      // in this case you need only one pipeable operator, switchMap.
      // switchMap is a 'higher order' operator, i.e. an operator which returns
      // another Observable (as part of the transformation performed within
      // the pipe) - other higher order operators are concatMap, mergeMap (akak flatMap, exaustMap)
      switchMap((params) => {
         let classCode = params.get('cc') ?? '';
         classCode = decodeURIComponent(classCode);
         if (classCode.match(ALPHABETS_REGEX)) {
            // in this case you return the Observable returned by fetchStudents
            return this.studentSvc
              .fetchStudents({
                sec: sectionCode,
              })
         }
         // in the case the code does not match ALPHABETS_REGEX you have to return
         // another Observable to respect the signature of switchMap.
         // This Observable could be, for instance, an Observable that returns
         // an empty array (or anything else, depending on your requirement)
         return of([])
      })
    ).subscribe(
    // do what you need to do
    )
    

    You may find this article interesting.