I need to wait for some API call before letting page in my route to load. Basically we have A/B testing enabled (which is API call) and based on that will have to either load Component assosiated with that route or redirect to different url.
To do that I was trying to use resolver that returns Observable<boolean>
. Here is code:
export class RedirectResolveService implements Resolve<Observable<boolean>> {
private empty = new Observable<boolean>();
constructor(private apiService: ApiService, private router: Router) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> {
return this.apiService.get("/api/abtest/mypage").pipe(
tap((isOn) => {
if (!isOn) {
window.location.href = "/welcome-page";
}
}),
first()
);
}
}
Then I add this in the route:
{
path: 'new-page',
component: NewPageComponent,
resolve: {
redirect: RedirectResolveService,
},
},
And then in NewPageComponent I add subscription in the constructor:
export class NewPageComponent {
constructor(private route: ActivatedRoute) {
this.route.data.subscribe();
}
}
It works but for the case when redirect happens I see first NewPageComponent rendered and then redirect happening. That makes sense since I subscribe to my Observable when Component initializes and thus only start redirect after that.
Is there way to make redirect logic without Component being initialized?
Using route guard it would be something like this
@Injectable({
providedIn: "root",
})
export class RedirectGuard implements CanActivate {
constructor(
private _authService: AuthService,
private _router: Router,
private apiService: ApiService
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
return this.apiService.get("/api/abtest/mypage").pipe(
tap(isOn => isOn || this._router.parseUrl("/welcome-page")),
first()
);
}
}