store icon indicating copy to clipboard operation
store copied to clipboard

How to get @select to return an Observable instead of AnonymousSubject?

Open yohanfernando opened this issue 8 years ago • 10 comments

At the moment the @select returns an AnonymousSubject which is breaking the CanLoad and Resolve routing guards in Angular 4 (or 2 and above). It seems just these two router guards cannot handle it as the CanActivate deals with AnonymousSubject without an issue.

Is there any way that I can force it to return an Observable or even a 'normal' Subject?

Thank you

yohanfernando avatar Apr 19 '17 17:04 yohanfernando

If you have your CanLoad use ngRedux.select(.....) are you getting the same issue, just wondering if this is applying to just the decorator, or select in general.

e-schultz avatar Apr 20 '17 21:04 e-schultz

It happens when using the @select as well as ngRedux.select(.....).

I did a bit of investigating with the hope of submitting a PR. However, being from a Java background and being relatively new to JS/TS world, I don't know much of RX to be able to resolve this.

This happens as soon as any operator (filter / distinctUntilChanged / etc) is applied to the this._store$ variable (which is meant to be a BehaviorSubject) in the src/components/ng-redux.ts.

this._store$ = new BehaviorSubject<RootState>(null)
    .filter(n => n !== null)
    .switchMap(n => {
        return Observable.from(n as any);
    }) as BehaviorSubject<RootState>;

Although it's casted to a BehaviorSubject, it still get assigned as an AnonymousSubject.

The returned Observable also get changed to an AnonymousSubject when the this._store$.distinctUntilChanged is applied from the select<S>(...) method.

Hopefully, that will give some indication to what's happening and appreciate your help.

Thanks Yohan

yohanfernando avatar Apr 21 '17 07:04 yohanfernando

Still looking into this, thanks for the insight.

In the route guard, could you do something like:

ngRedux.select('selector').asObservable(); // hides the subject, converts to observable

If that works out, I'll see if it's possible to update select to return the Observable<T> without introducing any breaking changes.

e-schultz avatar May 09 '17 21:05 e-schultz

It didn't work :(

I couldn't directly use asObservable() and had to cast to a Subject and then use asObservable().

(<Subject<any>>this.ngRedux.select<any>('selector')).asObservable();

I think the fact that there is an AnonymousSubject in the observer chain is causing it to break. Do you think it's a bug in the @angular/router / Resolve?

Another suggestion: if we bring the operators individually rather than hoping Webpack/SystemJS import the correct operators, do you think it might resolve the issue? I have a feeling when the filter, switchMap and the distinctUntilChanged are applied to the ngRedux store it's importing operators that generate AnonymousSubject rather than a simple Subject which is the root cause of this problem - I may be wrong.

import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/distinctUntilChanged';

Until there is a permanent fix, I am returning a Promise and within that subscribing to the store and only resolving the Promise when expected data arrive - a workaround :).

yohanfernando avatar May 10 '17 16:05 yohanfernando

I know @SethDavenport has done quite a bit of refactoring of the guts of NgRedux - wondering if this is still an issue with the newer releases?

e-schultz avatar Jul 11 '17 19:07 e-schultz

Concerning Angular router and redux with @select I posted an issue here: https://github.com/angular/angular/issues/18991

Does @select complete?

markusfalk avatar Sep 11 '17 09:09 markusfalk

Any updates on this? I need to .concatMap Observables with the @select decorator, but it's not possible because @select always return an AnonymousSubject.

lvidal1 avatar Oct 02 '17 05:10 lvidal1

@markusfalk @lvidal1 observables returned from @select and .select will not complete - they are Observable slices of state that remain active.

If you need to use them in a context where they need to 'complete' - such as in a resolver, route guard, etc - using an operator like .first() or .take() will get the current value and complete the observable.

e-schultz avatar Dec 19 '17 18:12 e-schultz

Facing the same issue. Gone through the comments however didn't get the proper solution.

Can anyone help how to get the normal object while using @select?

swapnilvaidankar avatar Aug 12 '19 11:08 swapnilvaidankar

Is there any update on this issue?

AnkurArora007 avatar Oct 07 '19 09:10 AnkurArora007