I am using angular and firestore. I'm checking firestore for a value inside my route guard.
I have found that on page refresh, it returns as undefined. However, if I just hardcode a return of true or false, it works.
Any logs within my if statement always return correctly, but doesn't seem to be updating my global variable for some reason.
If I use my site navigation to get back to the root and navigate through my site, it works correctly. However, when I refresh the page, it returns as undefined.
Could it be a scoping issue?
Route Guard
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Subscription } from 'rxjs/Subscription';
//testing
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
@Injectable()
export class CheckBillingService implements CanActivate {
private _subscription: Subscription;
private userBillingDocRef: AngularFirestoreDocument<any>;
userBilling: Observable<any>;
public activeAccount:Observable<boolean>
constructor(private authService: AuthService,
private router: Router,
private auth: AngularFireAuth,
private readonly afs: AngularFirestore) {}
canActivate(): Observable<boolean> {
this.authService.user.subscribe((user) => {
if (user) {
var userId = user.uid;
this.userBillingDocRef = this.afs.doc('user_billing/${userId}');
this.userBilling = this.userBillingDocRef.snapshotChanges();
this.userBilling.subscribe((value) => {
const data = value.payload.data();
if (data.account_status == "Active") {
this.activeAccount = Observable.of(true);
console.log('inside if statement for active = ', this.activeAccount);
} else {
this.activeAccount = Observable.of(false);
console.log('inside if statement for not active = ', this.activeAccount);
this.router.navigate(['resubscribe']);
return Observable.of(false);
}
console.log('userBilling.subscribe = ', this.activeAccount);
});
console.log('just outside userBilling.subscribe = ', this.activeAccount);
}
});
// When refreshig my page, this returns as undefined.
// If I navigate to the correct page and work my way through the site it works fine
// However, refresh returns undefined.
console.log('out of auth = ', this.activeAccount);
return this.activeAccount;
}
}
According to your code the page will run before your observable method is returned as it's running asynchronously, instead return the full method as observable like so
canActivate(): Observable<boolean> {
return Observable.create(observer=> {
this.authService.user.subscribe((user) => {
if (user) {
var userId = user.uid;
this.userBillingDocRef = this.afs.doc('user_billing/${userId}');
this.userBilling = this.userBillingDocRef.snapshotChanges();
this.userBilling.subscribe((value) => {
const data = value.payload.data();
if (data.account_status == "Active") {
this.activeAccount = Observable.of(true);
// observe here
observer.next(true)
console.log('inside if statement for active = ', this.activeAccount);
} else {
this.activeAccount = Observable.of(false);
// observe here
observer.next(false)
console.log('inside if statement for not active = ', this.activeAccount);
this.router.navigate(['resubscribe']);
}
console.log('userBilling.subscribe = ', this.activeAccount);
});
console.log('just outside userBilling.subscribe = ', this.activeAccount);
}
});
});
// When refreshig my page, this returns as undefined.
// If I navigate to the correct page and work my way through the site it works fine
// However, refresh returns undefined.
console.log('out of auth = ', this.activeAccount);
}
Observe where I wrapped everything in Observer.create
which you can learn more here https://stackoverflow.com/a/44334611/5836034
then observer.next
will return what you really want the canActivate
hook to react on
// observe here
observer.next(true)
observer.next(false)