New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guards and Resolvers don't wait for APP_INITIALIZER, if RouterModule initialNavigation: 'enabled' is set #1623
Comments
I just found out, that |
Can you clarify this in the context of marking this as a regression? I tested the stackblitz demo, going all the way back to Angular 6.0.0 and the behavior remained the same: when |
I've looked into the docs and the
That said, if |
The error appeared after I upgraded to Angular 9. Only later I found out, that 'initialNavigation' was set automatically during the upgrade. Therefore I agree with you, that this would classify as a migration bug. I think the value was set, because I'm using SSR. |
@felixfiskare - Can you update the configuration you're loading to be an |
Thank you for that pointer @atscott and sorry for the delay. It took some time to encapsulate everything in observables, but now everything works! |
@felixfiskare This is caused by the NgUniversal schematics, we added it to avoid flicker when bootstrapping on the client. We'll move this issue over to angular/universal so that we can track a proper resolution. This may be a warning or a prompt, or possibly a link to documentation about certain pitfalls with adding |
First phase of this is tracked in #1730, we'll add this section once it's merged. |
Hi Guys, is this fix currently merged into v10.1.x ? thanks! |
@BruneXX I tried with 10.1.1 and 10.1.2 and the issue still remains |
Hi @AceVentura Sad to hear, I think we'll need to wait for this one.. Thanks |
Hi, any update of when is this going to be merged? Thanks! |
Hi, I'm facing the same issue here too |
Hi @CaerusKaru, |
@nils-thomann the issue is still there (v11.1.1). Your only choice is to change your project to not be dependent on APP_INITIALIZER. That's what I've done. |
Hi @AceVentura, thanks for your response. Do you have some recommendations were to do stuff that has to be done before the initial navigation without using the |
@nils-thomann, I believe that really depends on your project. For example, in my project I have dynamic routes, which I only know by doing an API Call. |
Yep, same issue here. |
This is big issue for my case since I generally use I tried wrapping all routes like { path: "", component: RootComponent, canActivate: [ EnsureAuthGuard ], children: [
{ path: "", component: SomeComponent, canActivate: [ DoSomethingWithAuthGuard ] } // errors or always not accessable.
] } but as mentioned angular issue, this is currently not working since all guard are runs in parallel. Since So currently, only solution is resolve required states before all guards run. constructor(
private auth: EnsureAuthGuard
) { }
async canActivate() {
await this.auth.ensureAuth();
// ... now auth state surely resolved ....
} Hope v12 can resolve this. |
Hi guys, here's the workarounds I'm applying on my project (v11). It works with SRR as well. Hope it helps someone
// app.module.ts
function initializeApp(
authenticationService: AuthenticationService,
): () => Promise<any> | undefined {
return () => {
if (typeof window !== 'undefined') {
return authenticationService.getUserInfo().toPromise();
}
return;
};
} // authentication.service.ts
export class AuthenticationService {
userInfo: UserLoginInfo | null | undefined;
userInfoSubject = new ReplaySubject<UserLoginInfo | null>(1);
constructor(
@Inject(PLATFORM_ID) private platformId: Record<string, unknown>,
@Optional()
@Inject('authenticatedUserData')
public authenticatedUserDataFromSsr: UserLoginInfo | null | undefined,
private httpClient: HttpClient,
private transferStateService: TransferStateService,
) {
if (isPlatformServer(this.platformId)) {
this.transferStateService.set<UserLoginInfo | null | undefined>(
'authenticatedUserData',
authenticatedUserDataFromSsr
);
}
this.userInfo = this.transferStateService.get('authenticatedUserData');
if (this.isFetched(this.userInfo)) {
this.userInfoSubject.next(this.userInfo);
}
}
isFetched(data: any): boolean {
return typeof data !== 'undefined';
}
getUserInfo(): Observable<UserLoginInfo | null | undefined> {
if (this.isFetched(this.userInfo)) {
return of(this.userInfo);
}
return this.httpClient.get<{ user: UserLoginInfo | null }>('/userData').pipe(
map((response) => response.user),
catchError((err) => {
this.userInfoSubject.next(null);
return of(null);
}),
tap((userInfo) => {
this.userInfo = userInfo;
this.userInfoSubject.next(userInfo);
})
);
}
...
} // authentication.guard.ts
export class AuthenticationGuard implements CanActivate {
constructor(private authenticationService: AuthenticationService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.authenticationService.userInfoSubject.pipe(
map((userInfo) => {
if (userInfo) {
return true;
}
return this.router.parseUrl('/');
})
);
}
} |
As per above comments, this is working as intended. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
🐞 bug report
Affected Package
@angular/router/RouterModule
@angular/core/APP_INITIALIZER
Is this a regression?
Yes, this used to work all the way up until Angular 8.2.14.
This bug started to appear once I updated to Angular 9 (9.0.7)
EDIT: I updated to Angular 9.1, but the problem persists.
Description
After Upgrading I noticed, that some parts of my application wouldn't start any longer, because the configuration they are depending on is empty.
I used to load this configuration from a config file on my server. I'm using APP_INITIALIZER for this. Upon further investigation I found out, that my guards and resolvers run before my APP_INITIALIZER promise resolves.
Finally I could pin-point this error to app-routing.module.ts. When I uncomment
initialNavigation: 'enabled'
then the guards and resolvers wait till the APP_INITIALIZER promise resolve.Once enabled, the guards and resolvers run immediately and don't wait for APP_INITIALIZER.
🔬 Minimal Reproduction
Open the console to see when different parts of the application get executed.
MinimalGuard and ResolverService should get executed after AppInitializerService Promise resolved, but unfortunately they get executed before.
https://stackblitz.com/github/felixfiskare/ResolverAndGuardBeforeInit
https://github.com/felixfiskare/ResolverAndGuardBeforeInit
🔥 Exception or Error
🌍 Your Environment
Angular Version:
The text was updated successfully, but these errors were encountered: