user8516249
user8516249

Reputation:

Angular / Typescript / Firestore - How to return an observable value within an if statement

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

Upvotes: 1

Views: 930

Answers (2)

Lazar Ljubenović
Lazar Ljubenović

Reputation: 19754

Observables can be asynchronous; they're usually used for this purpose. Code outside of subscribe is in such cases executed before one inside subscribe.

That's why it seems like it's "not updating" variables. It is, but you're not accessing them at the correct time. It works when you hardcode the values because then subscribe is executed synchronously.

Upvotes: 1

Theophilus Omoregbee
Theophilus Omoregbee

Reputation: 2503

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)

Upvotes: 5

Related Questions