0
votes

I have the following initialization at the top of my angular component.

public myDataObservable$: Observable<MyData[]>;

Somewhere in my component I make the following call to an Ngrx store using a selector to get back data for the observable. All of this works fine and I get the data back I wanted.

this.myDataObservable$ = this.store.pipe(select(MyDataStore.getMyData));

I need to know when this observable completes. I need to set a boolean that will turn off a loading indicator when all of the data the observable is trying to get finishes. This is done through a web service.

Because the source of the observable comes from somewhere else I cannot hang a 'complete' call back () => {this.loadingIndicator = false} like this.

I have tried various Rxjs operators such as TakeUntil and Finalize with no luck. These operators get called right away and my loading indicator shuts off as fast as it went up.

I scoured the internet and tried many different solutions but I cannot find an answer. Thanks for taking the time to look at this.

2
"I need to know when this observable completes" - if you are just turning off a loading indicator, can't you just turn it off when you receive the first emission? Something like this: this.myDataObservable$ = this.store.pipe(select(MyDataStore.getMyData), tap(() => this.loading = false)) - BizzyBob
Or is your problem that the observable initially emits, but the store is still fetching an updated value in the background? - BizzyBob
The store is still fetching data in the background which is expected. Its connected to a asynchronous service. Any attempt to use your tap suggestion or .subscribe(() => {this.loadingIndicator = false}) immediately execute that code and turns the loadingIndicator false meanwhile its still fetching data. I mainly need to know when the observable stops getting data and thats when I want to flip the loading indicator. - Bryan Harrington
what does it mean to "stop getting data"? I was assuming that when you receive a value, that means it was loaded. But, if it initially gives you a cached value AND you don't really want this cached value, you could use skip(1) to ignore the first emission. - BizzyBob
The data is not cached at this point. We need to fire an effect to get it from the server, save it and then we use our selector to pull it from the store. Lets assume that there would be 500 possible records that the observable could retrieve. It could take 5 seconds to get that data. From the time the observable starts getting data and to the point it stop at record 500 I want the loading indicator to stop showing. Of course we don't know how many records we get back we just know were are getting records. I want to know when it stops getting records if that point is even possible to know. - Bryan Harrington

2 Answers

0
votes

I'm not 100% certain what you are asking for; but why wouldn't the code below work? I don't know what type of store you are using either (ngxs, ngrx, ???). There could be a property in the store that sets the loading indicator when called. It can then be updated in state again when it comes back successful or with an error.

this.myDataObservable$ = this.store.pipe(select(MyDataStore.getMyData));

this.myDataObservable$.subscribe(
  next: x => console.log('Observer got a next value: ' + x),
  error: err => console.error('Observer got an error: ' + err),
  complete: () => this.loadingIndicator = false),
);

0
votes

The solution was to place the boolean for the loading indicator in the state and set it within the reducer. When the Data is populating the loading reducer is called and the state boolean is set to true. When the loading success reducer is called it will the the state boolean to false.

After that I created a selector to get the boolean state.

I now initialize this as an Observable boolean and within my ngOnInit method I can declare the following,

this.showLoading$ = this.store.pipe(select(TechnopediaStore.getisLoadingData));

With that I just have to apply this to the structure directive in my .html and it works perfectly.