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!
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)))
);
})
);