1

In my Angular project, I came into one case as following:
In the Frontend side I have a language system, user can choose one language from the options. And each time user choose a new language I need to invoke a server side method subscribe with it, and if the invoke run successfully, it will return to a subscriptionid.
Next time, when user change a new language, I need to create a new subscription. But before that, I need to unsubscribe the current one. The demo code goes as following:

  this.start().subscribe((res) => {
    // store current subscription id   
    this.currentSubscriptionId = res.SubscriptionId;
  });

  private start(): Observable<{ [key: string]: string }> {
      return this.xService.language$.pipe(
          switchMap((language) =>
            this.unsubscribe().pipe(
              switchMap((_) => this.invoke("subscribe",language)) // this.invoke return observable<any>
            )
          )
      );
  }

  private unsubscribe(): Observable<any> {
    if (this.currentSubscriptionId) { // default initial value is empty string  ""
      return this.invoke("Unsubscribe", {
        Id: this.currentSubscriptionId
      });
    } else {
      return of("");
    }
  }

so i use a state variable currentSubscriptionId for this flow. It's default value is empty string, so for the first time, no need to invoke the unsubscribe method, return an of observable.

in the current implementation, I capsulate the logic inside function of unsubscribe and based on the state variable currentSubscriptionId to handle the flow.

is there any other optimized solution for this case? do this kind of judgement control in a more RxJS style.

Chris Bao
  • 2,418
  • 8
  • 35
  • 62

1 Answers1

0

I think it's time to utilize the "finalize" operator, which invokes the given function as its subscription gets disposed.

const { Subscription, BehaviorSubject, Observable, of, never, interval } = rxjs;

const Rx = rxjs.operators;

let cleanUp = new Subscription();

function start() {
  return selectedLang.pipe(
    Rx.switchMap(lang => callSubscribeAPI(lang)),
    Rx.switchMap(id =>
      never().pipe(
        Rx.startWith(id),
        Rx.finalize(() => cleanUp.add(callUnsubscribeAPI(id).subscribe()))
      )
    )
  )
}

// Mock of language selection UI:

let selectedLang = new BehaviorSubject("ja");

// Server-side API mocks:

let subscriptionIdCounter = 0;

function callSubscribeAPI(lang) {
  let id = ++ subscriptionIdCounter;
  console.log(`[server] subscribe: ${lang}@${id}`);
  return of(`${id}`);
}

function callUnsubscribeAPI(id) {
  console.log(`[server] unsubscribe: ${id}`);
  return of();
}

// Usage:

start().subscribe(console.log);

interval(300)
 .pipe(Rx.take(4))
 .subscribe(i => 
   selectedLang.next(["en", "kr", "cn", "ja"][i])
 );
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.min.js"></script>
findall
  • 2,176
  • 2
  • 17
  • 21