0
votes

I'm looking to subscribe to an observable and use some methods on it to ensure that it's debounced and that previous requests are cancelled

private _allBulls = new BehaviorSubject<Sire[]>([]); 
allBulls$ = this._allBulls.asObservable();

private apiChange = new Subject<ApiChange>();
apiChange$ = this.apiChange.asObservable().distinctUntilChanged().debounceTime(1000);

I've gotten to here and I can subscribe in my component and then call this method from the component

this.subscription = this.selectionService.apiChange$.subscribe(
(data) => {
  this.selectionService.getSireData(data); 
})

The method getSireData

getSireData(apiChange: ApiChange) {
  console.log("getSireData")

  this.updateApiSettings(apiChange);

  const headers = new Headers({'Content-Type': 'application/json'})

  options = new RequestOptions({ headers: headers});

  this.http
   .post(`${this.baseUrl}SireSearch/Scope/Filtered`, this.apiSettings, options)
   .map(this.extractData)
  .subscribe(data => this._allBulls.next(data))
}

The subscription in another component to make changes reflective of the observable

this.selectionService.allBulls$.subscribe(() => this.selectionService.applyGridSettings());

I can't use .switch or the .switchMap operator however because it expects a returned observable. So I think I need to come up with a different structure. I also would prefer to simply subscribe to the apiChange$ and not call the service method from the subscription.

2

2 Answers

1
votes

When you see

this.selectionService is used multiple times from the component for the same process, it likely means you want to put that entire logic within the service. This way that internal logic is abstracted for service users.

Also, putting it together will allow you to make a switchMap on the httpRequest and cancel previous requests that were pending. Note that the canceled requests will still run on the server side, but at least your client will discard any results of obsolete requests.

In your service, you will want to have

private apiChange = new Subject<ApiChange>();
apiChange$ = this.apiChange
.asObservable()
.distinctUntilChanged()
.debounceTime(1000)
.switchMap( (data) => { 
  this.updateApiSettings(data);

  const headers = new Headers({'Content-Type': 'application/json'}), 
  const options = new RequestOptions({ headers: headers}); 

  return this.http
             .post(`${this.baseUrl}SireSearch/Scope/Filtered`, this.apiSettings, options) 
}) 
.map(this.extractData); 

and a service method that will make the subscription to the service like:

startSubscription() { return this.selectionService.allBulls$.subscribe(() => this.selectionService.applyGridSettings()); }

and within the component, you will only want to subscribe to it on initialization and unsubscribe when the component is destroyed so

ngOnInit() {this.subscription = this.service.startSubscription();} 
ngOnDestroy() {this.subscription.unsubscribe(); }

This way when you navigate away, the subscription stops, when you navigate to that route, the subscription comes back on line.

1
votes

Maybe something like this, in your data-Service:

class YourServiceClass {
    private updateSireOnApiChange$ = this.serviceWithApiChanges.apiChange$
        .switchMap(apiSettings => {
            const headers = new Headers({'Content-Type': 'application/json'})
            const options = new RequestOptions({ headers: headers});

            return this.http
                .post(`${this.baseUrl}SireSearch/Scope/Filtered`, this.apiSettings, options)
                .map(this.extractData)
        })
        .do(data => this._allBulls.next(data));

    constructor(private http: Http, private serviceWithApiChanges: ServiceWithApiChanges) {
        this.updateSireOnApiChange$
            .catch(() => this.updateSireOnApiChange$) // just resubscribe to a fresh stream on any error to keep this active forever
            .subscribe();
    }
}