4

I'm using an async pipe in angular to monitor an observable coming from an rxjs store. The component's ngOnInit looks like this

ngOnInit() {
  this.userRole$ = this.store.select(selectUserProfile).pipe(
    filter(user => !!user),
    map(user => parseUserRole(user.role))
  );
}

The component template looks like this

<p> User role is {{ userRole$ | async }} </p>

After the user logs in, the message on the page remains an empty string

In the component.ts I added the following the code to debug the issue

this.userRole$.subscribe(userRole => {
  alert(`new user role is ${userRole}`);
});

After the user logs in, I get an alert saying "new user role is admin", however, the pipe in the html template doesn't update.

When I replaced the store select() with a dummy value using of() and everything worked as expected, so I'm pretty sure the problem is something to do with rxjs.

The auth reducer (which is firing) looks like this (

export function reducer(state = initialAuthState, action: AuthActions): AuthState {
    switch (action.type) {
        /// ...CODE OMITTED
        case AuthActionTypes.UserProfileRetrieved:
            alert(`setting user profile ${action.payload.userProfile}`)
            return { ...state, userProfile: action.payload.userProfile }
        default:
            return state;
    }
}

I've tried making sure the UserProfileRetrieved action is dispatched from inside ngZone.run() but that didn't make difference. I don't really know how else to go about debugging this. Any pointers would be greatly appreciated. Thank you!

2
  • 1
    If you can add tap operator to the pipeline it will be a good debugging point and if you can provide a stackblitz with the example it will be great! Commented Feb 2, 2020 at 1:20
  • Hi, thanks for your response! I added a tap() operator and the details were logged as expected. I can confirm that the observable is working, but the problem seems to be something to do with the async pipe... I can't make a stackblitz, unfortunately, as this problem only appears in a cordova project when using auth0. I tried reproducing the issue with a dummy observable using of() and it worked as expected. Commented Feb 2, 2020 at 9:44

2 Answers 2

1

Can you try this code and see if it works fine. Have added tap operator to see if such changes/data emitted from the store took place.

this.userRole$ = this.store
   .select(selectUserProfile)
   .pipe(
     tap(user => console.log('FETCHED:', user)),        // Console if user data exists
     filter(Boolean),                                   // Change !!user to Boolean
     tap(user => console.log('FILTERED:', user)),       // Console if user exists after filter 
     map(user => parseUserRole(user.role))
     tap(user => console.log('MAPPED:', user)),         // Console if user is mapped
   );

NOTE:

That the store will only send it's response once the prior/parent service is invoked.

Example:

// If along with the getUsers() functionality has a piped storeService in it
// http.get(url).pipe(tap(data => this.storeService.set('users', data)))
this.userService.getUsers().subscribe();    

// You can then initialize your store to get the data invoked/set above
this.user$ = this.store.select('users');
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the response! I've added those tap() operators and get the following output. FETCHED: null FETCHED: null FETCHED: null FETCHED: { ... } FILTERED: { ... } MAPPED: { ... } FETCHED: { ... } FILTERED: { ... } MAPPED: { ... } FETCHED: { ... } FILTERED: { ... } MAPPED: { ... } There are three pipes on the template which is why everything appears to firing three times. Everything in the pipeline seems to be working fine, it just seems that for some reason the pipe operator isn't picking up the latest changes from the store. I'm really stumped on where to go from here,,,
Can you place on "ngAfterViewInit" instead of "ngOnInit", im guessing that your store isn't ready/initialized yet and see if it has a data on it?
0

This turned out to be caused by a side-effect of the auth0 native app login flow. The app router was configured to use hash-based routing in order to support Cordova. After getting the login token from auth0, we were clearing the hash to remove the token information. Any store updates after this point were not being reflected in the async pipes, but updates before this were.

If anyone is having a similar problem make sure that clearing the hash is the last thing you do before navigating to the post authorization URL. Thanks @Shorbagy and @KShewengger for your help.

Here's the code I used to do this

@Effect()
    loginComplete$ = this.actions$.pipe(
        ofType<LoginComplete>(AuthActionTypes.LoginComplete),
        exhaustMap(() => {
            return this.authService.authResult$.pipe(
                map((authResult: any) => {
                    if (environment.platform.name === Platforms.BROWSER) {
                        window.location.hash = '';
                    }

                    if (authResult && authResult.accessToken) {
                        this.authService.setAuth(authResult);
                        return new LoginSuccess();
                    } else {
                        debugger;
                        return new LoginFailure({ message: 'no accessToken', payload: authResult })
                    }
                }),
                catchError(error => of(new LoginFailure(error)))
            );
        })
    );

2 Comments

May I ask how you cleared the hash ?
@Stephane Edited the answer to include the code. Hope that helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.