Angular Observable undefined,尽管已在构造函数中设置并正确订阅(使用firebase)。

问题描述 投票:0回答:1

我的组件错误: ERROR TypeError: "this.brandService.getCurrentBrand(...) is undefined"

问题是里面的代码。this.auth.currentUser.then() 块的BrandService构造函数没有在组件订阅它之前运行,因此组件得到一个未定义的错误。

我的 组成部分 在我的BrandService里面订阅了一个 "currentBrand "的Observable。

  private currentBrand: Brand;

  ngOnInit(): void {
    this.brandService.getCurrentBrand().subscribe((brand) => {
      this.currentBrand = brand;
    });
  }

The 品牌服务 是在构造函数中设置 "currentBrand",并且有getCurrentBrand()方法来返回它。

  private currentBrand: Observable<Brand>;

  constructor(
    private afs: AngularFirestore,
    private auth: AngularFireAuth,
    private userService: UserService
  ) {
    this.brandsCollection = this.afs.collection('brands', (ref) =>
      ref.orderBy('name', 'asc')
    );

    this.auth.currentUser.then((authUser) => {
      console.log('this is logged prior to the undefined error');

      this.userService.getUserByEmail(authUser.email).then((user) => {
        console.log('for some reason, this is logged after the undefined error, need this to run prior to in order to eliminate the error');
        this.currentBrand = this.getBrand(user.defaultBrandId);
      });
    });
  }

  getCurrentBrand(): Observable<Brand> {
    return this.currentBrand;
  }

  getBrand(id: string): Observable<Brand> {
    this.brandDoc = this.afs.doc<Brand>(`brands/${id}`);

    this.brand = this.brandDoc.snapshotChanges().pipe(
      map((action) => {
        if (action.payload.exists === false) {
          return null;
        } else {
          const data = action.payload.data() as Brand;
          data.id = action.payload.id;
          return data;
        }
      })
    );

    return this.brand;
  }

我不知道我在这里做错了什么. 我认为BrandService构造函数中的一切都应该在组件的ngOnInit之前运行,因此这个未定义的错误不应该发生。我正确地将构造器中的代码放在了.then()方法中,该方法在Promises解析时执行。我似乎无法理解这个问题......

angular firebase promise observable
1个回答
0
投票

你可以让 currentBrand a RxJS BehaviorSubject. 这是一个常见的承诺和观测值混合的情况。我使用的是RxJS from 将承诺转换为观测值,并使用 switchMap 操作员,以最终在 this.getBrand() 方法。

试试下面的方法

private currentBrand = new BehaviorSubject<Brand>(null);

constructor(
  private afs: AngularFirestore,
  private auth: AngularFireAuth,
  private userService: UserService
) {
  this.brandsCollection = this.afs.collection('brands', (ref) =>
    ref.orderBy('name', 'asc')
  );

  from(this.auth.currentUser).pipe(
    switchMap((authUser) => {
      console.log('this is logged prior to the undefined error');
      return from(this.userService.getUserByEmail(authUser.email)).pipe(
        switchMap((user) => {
          console.log('for some reason, this is logged after the undefined error, need this to run prior to in order to eliminate the error');
          return this.getBrand(user.defaultBrandId);
        })
      )
    })
  ).subscribe(
    response => {
      this.setCurrentBrand(response);      // <-- push the response to `currentBrand` observable here
    },
    error => {
      // handle error
    }
  );
}

getCurrentBrand(): Observable<Brand> {
  return this.currentBrand.asObservable();
}

setCurrentBrand(brand: Brand) {
  this.currentBrand.next(brand);
}

组成部分

ngOnInit(): void {
  this.brandService.getCurrentBrand().subscribe((brand) => {
    if (brand) {
      this.currentBrand = brand;
    }
  });
}

0
投票

所以你所面临的问题是因为你的代码是异步执行的。我已经试着解释了这个问题,在你的组件内部,你试图在ngoninit方法中获取它的值,就像下面给出的private currentBrand::。

    //When the instance of ur service get created this thing is undefined 
    private currentBrand: Observable<Brand>;

      constructor(
        private afs: AngularFirestore,
        private auth: AngularFireAuth,
        private userService: UserService
      ) {
        this.brandsCollection = this.afs.collection('brands', (ref) =>
          ref.orderBy('name', 'asc')
        );
        // this is async function which will take some time
        this.auth.currentUser.then((authUser) => {
          console.log('this is logged prior to the undefined error');
           // this again is async operation
          this.userService.getUserByEmail(authUser.email).then((user) => {
            console.log('for some reason, this is logged after the undefined error, need this to run prior to in order to eliminate the error');

            // ONCE ALL THE ASYNC OPERATION ARE DONE YOU ARE ASSINGING THE VALUE HERE
            this.currentBrand = this.getBrand(user.defaultBrandId);
          });
        });
      }
      // SO it will take some time to set value 
      //Till that time currentBrand will be undefined
      getCurrentBrand(): Observable<Brand> {
        return this.currentBrand;
  }

在你的组件内部,你试图在ngoninit方法中获得它的值,就像下面给出的private currentBrand: Brand;

 ngOnInit(): void {
    this.brandService.getCurrentBrand().subscribe((brand) => {
      this.currentBrand = brand;
    });
  }

this.brandService.getCurrentBrand() / 这个值在你所有的承诺得到解决之前都是未定义的。

我希望你明白了这个问题。现在的解决方法是将currentBrand作为行为主体,然后在内部承诺上做下一步。

currentBrand : =new BehaviourSubject(initial value);

在你的承诺里面,这样做。

currentBrand.next('value you get from ur promise' )
© www.soinside.com 2019 - 2024. All rights reserved.