Angular/Typescript/Firestore – как вернуть наблюдаемое значение в операторе if

Я использую angular и firestore. Я проверяю firestore на наличие значения внутри моей защиты маршрута.

Я обнаружил, что при обновлении страницы он возвращается как undefined. Однако, если я просто жестко запрограммирую возврат true или false, это сработает.

Любые журналы в моем операторе if всегда возвращаются правильно, но, похоже, по какой-то причине моя глобальная переменная не обновляется.

Если я использую навигацию по сайту, чтобы вернуться к корню и перемещаться по моему сайту, он работает правильно. Однако, когда я обновляю страницу, она возвращается как неопределенная.

Может ли это быть проблемой области видимости?

Защита маршрута

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

person Community    schedule 12.01.2018    source источник


Ответы (2)


В соответствии с вашим кодом страница будет работать до того, как ваш наблюдаемый метод будет возвращен, поскольку он работает асинхронно, вместо этого верните полный метод как наблюдаемый, например

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

        }

Обратите внимание, где я завернул все в Observer.create, о чем вы можете узнать больше здесь https://stackoverflow.com/a/44334611/5836034

тогда observer.next вернет то, на что вы действительно хотите, чтобы хук canActivate реагировал на

  // observe here 
        observer.next(true)
    observer.next(false)
person Theophilus Omoregbee    schedule 12.01.2018
comment
Это потрясающе. Большое спасибо за быстрый ответ. Действительно хорошая информация, чтобы знать для тех, кто плохо знаком с этим. Я отмечу это как ответ через 2 минуты. - person ; 12.01.2018
comment
Спасибо за новость, Тео. Приятно получить ответ, в котором кто-то предоставляет реальную образовательную ценность для вопроса с помощью ресурсов и кода. Очень благодарен. - person ; 12.01.2018

Наблюдаемые объекты могут быть асинхронными; они обычно используются для этой цели. Код вне подписки в таких случаях выполняется перед кодом внутри подписки.

Вот почему кажется, что он «не обновляет» переменные. Это так, но вы не обращаетесь к ним в нужное время. Это работает, когда вы жестко задаете значения, потому что тогда подписка выполняется синхронно.

person Lazar Ljubenović    schedule 12.01.2018
comment
Спасибо Лазар. Я ценю ответ. Приведенный выше ответ Тео является ответом и соответствует тому, что вы говорите. Спасибо еще раз. - person ; 12.01.2018
comment
Видя, что вы не на ТАК: не нужно лично благодарить в комментариях. Проголосовать и/или принять ответ — обычно правильный путь. Рад, что вы нашли решение! - person Lazar Ljubenović; 12.01.2018