angularrxjsangular-observable

Using RxJS in Angular with conditional / combined subscriptions


in my Angular App I have an API service like so that contains two methods:

addComment(id: string, comment: string): Observable<any> {
    return this.http.post(`api/${encodeURIComponent(id)}/comment`, { comment }).pipe(
      map(this.apiUtils.extractData)
    );
  }


closeAccount(id: string): Observable<any> {
    return this.http.post(`api/${encodeURIComponent(id)}/closeaccount`, {}).pipe(
      map(this.apiUtils.extractData)
    );
}

Now in my app I have a component where I can close a user account and if a comment is added I wish to add a comment before closing the account, but this is conditional, sometimes a user doesn't need to add a comment before closing an account. In my component file I have created a method for this but I am a bit stuck with something... here is my component code where I collect my user data and comment from a form. If we have a comment we call the api to add the comment and when that resolves I call the API to close the account. If no comment has been submitted I just call the api to close the account. This is okay, but hardly eloquent! Please note I have reduced the code to improve readability.

constructor(private formBuilder: FormBuilder,
            public apiService: ApiService) {}

// i have omitted the code where I create my form and validation

closeAccount(): void {
    // get values from my form
    const id = this.closeAccountForm.controls.id.value;
    const comment = this.closeAccountForm.controls.closeAccountComment.value; 

    if (comment) {
        this.apiService.addComment(id, comment).subscribe(() => {
            this.apiService.closeAccount(id).subscribe(() => {
                // now do something
            });
        })
    } else {  
        this.apiService.closeAccount(id).subscribe(() => {
            // now do something
        });
    }
}

I was wondering if I can reduce the code and prevent the duplication of calling the closeAccount method. Does RxJS provide a way for me to apply the conditional logic in a method? What I have above works but is pretty ugly!

I'm currently reading the docs but sometimes people can provide an answer quicker. If I find an answer/solution I shall provide it here. Many thanks in advance. If my wording is bad please say so and I shall rework my question.


Solution

  • try this:

    const preCloseAction = comment ? this.apiService.addComment(...) : of(null);
    
    preCloseAction.pipe(
      switchMap(() => this.apiService.closeAccount(id))
    ).subscribe(() => {
      // now do something
    })
    

    or, if the result of comment doesnt matter during closeAccount call

    concat(
      !comment ? EMPTY : this.apiService.addComment(...),
      this.apiService.closeAccount(id)
    ).pipe(last()).subscribe(() => {
      // now do something
    })