The following code works correctly when the final if statement is true. Does not ever resolve the requested route when the final if statement is false. I've tried adding awaits and asyncs. I've tried moving the code into a separate function that returns an await with a boolean and nothing is working to resolve the route when it should. It always works when it should reject an redirect to settings.
If Statement
if(moduleSnapshot.size >= planLimit) {
this.toast.info(`You've reached your plan maximum, upgrade to add more ${mod}.`, 'Plan Maximum');
this.router.navigateByUrl('/settings/profile/subscription');
return false;
}
return true;
Full Router Guard
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { ToastrService } from 'ngx-toastr';
import { AngularFirestore } from '@angular/fire/firestore';
import { AuthService } from '../services/auth/auth.service';
import { SubscriptionsService } from '../services/subscriptions/subscriptions.service';
@Injectable({
providedIn: 'root'
})
export class SubscriptionGuard implements CanActivate {
constructor( private router: Router, private toast: ToastrService, private authService: AuthService, private subscriptionService: SubscriptionsService, private afs: AngularFirestore ) { }
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): any {
this.authService.userData.subscribe((observer1) => {
if(observer1) {
let subscriptions = this.subscriptionService.fetchUserSubscription(observer1.uid);
subscriptions.onSnapshot((observer:any) => {
observer.forEach((subscription:any) => {
if(subscription.exists) {
this.authService.allUserData.subscribe( async(userDataObserver:any) => {
let mod:string = state.url.split('/')[1];
await this.subscriptionService.fetchPlan(subscription.data().productID).then((plan:any) => {
let planLimit:number = parseInt(plan.metadata[mod]);
let companyUid:string = userDataObserver.companies[0].company;
this.afs.collection('companies').doc(companyUid).collection(mod).ref.get().then((moduleSnapshot:any) => {
if(moduleSnapshot.size >= planLimit) {
this.toast.info(`You've reached your plan maximum, upgrade to add more ${mod}.`, 'Plan Maximum');
this.router.navigateByUrl('/settings/profile/subscription');
return false;
}
console.log('Plan max not met, should resolve');
return true;
});
});
});
}
});
});
}
});
}
}
As per Angular's implementation, the
canActivatemethod (required by theCanActivateinterface) requires a return type.Without trying to dive to deep into the logic of your route guard, what I can see is that you're not actually returning anything. Because
userDatais an Observable, the subscription logic is handled asynchronously. This means that thecanActivatemethod is invoked by the router, the subscription logic is started asynchronously and then the method call resolves with no value.To fix the issue, you'll need to return an Observable stream which contains the boolean. For this I would suggest using rxjs
.pipe()in conjunction with the.switchMap()operator in order to preserve the subscription logic.