为什么我收到此错误:类型订阅不能分配给类型FirebaseListObservable <any>?

时间:2017-06-21 04:44:50

标签: angular ionic2 angularfire2

我正在尝试从/users列表中检索数据并收到此错误:

  

类型'订阅'不能分配给类型   'FirebaseListObservable'。类型中缺少属性'$ ref'   '订阅'。

下面是我的代码:

import { Injectable } from '@angular/core';

import { AngularFireAuth } from 'angularfire2/auth';
import firebase from 'firebase';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable  } from 'angularfire2/database';



@Injectable()
export class FbauthserviceProvider {

  user : FirebaseListObservable<any>;   
  email: string;

  constructor(public afAuth: AngularFireAuth, public afDb: AngularFireDatabase) {
    console.log('Hello FbauthserviceProvider Provider');
  }

  signup_with_username(email: string,password: string){
    this.email = email;

    this.user = this.afDb.list('/users', {
      query: {
        orderByChild: 'email',
        equalTo: this.email,
      },
      preserveSnapshot: true
    }).subscribe(snapshots => {
      let user_data = [];
      snapshots.forEach(snapshot => {
        user_data.push(snapshot.val());
      });
      console.log(user_data);
    });
  }
}

2 个答案:

答案 0 :(得分:1)

你的代码充斥着反模式和不必要的部分。

首先,不要使用preserveSnapshot。您不需要使用AngularFire。您可以直接订阅FirebaseListObservable发出的数组本身。一旦你拥有它,就没有必要迭代它并将其元素推送到其他一些数组 - 你已经有了数组,你可以按原样使用,或者映射,或存储(但见下文),或者其他什么。所以写一下:

this.user = this.afDb.list('/users', {
  query: {
    orderByChild: 'email',
    equalTo: this.email,
  }})
}).subscribe(users => {
  console.log("users are", users);
});

但这里仍有问题。 this.user不是您的意思:它将是subscribe返回的订阅。除了取消订阅之外,您无法对其进行任何操作。如果要“解包”用户列表并将其存储为本地静态属性,则需要在subscribe处理程序中将其分配给可用的位置:

.subscribe(users => {
  console.log("users are", users);
  this.users = users;
})

然而,展开observable并将其存储在静态属性中(通常)是一种反模式。问题是你不知道什么时候准备就绪。在最好的情况下,您必须在模板中包含与*ngIf="users"一起使用的位置,或者使用?中的存在性运算符users?.length来限定模板中对它的引用(这不是AoT友好的。)

相反,保持observable不变,并使用async管道直接在模板中取消引用它:

this.users$ = this.afDb.list('/users', {
  query: {
    orderByChild: 'email',
    equalTo: this.email,
  }});

<div *ngFor="let user of users$ | async">
  User is {{user.name}}
</div>

这里我遵循使用$表示可观察对象的后缀属性约定,这对于保持理智是有用的。

如果您只想要名称,那么您可以映射observable本身以创建一个可观察的名称数组:

this.names$ = this.users$.map(users => users.map(user => user.name));

请注意,这两个map来电不同。第一种是将 observable 映射到新的observable。第二个是将observable的用户数组 emit 映射到包含名称的新数组。现在在您的模板中:

<li *ngFor="let name of names$">{{name}}</li>

上面的讨论涉及组件。在您的情况下,您有一项服务。通常,服务的反模式是订阅一些可观察的并将值存储在静态本地属性中。问题是不会更新引用该服务上的属性的组件。相反,您的服务应该公开observables,并让消费者 - 通常是一个组件 - 解除引用/解包它们。

要查找手机号码匹配的用户,您仍然可以留在可观察的世界中:

this.matchingUsers$ = this.users$.map(users => users.filter(user => user.mobile === mobile));

将创建具有匹配移动号码的用户数组的可观察对象,如果没有匹配则将为空。一些消费模板可以将其用作

<div *ngFor="let matchingUser of userService.matchingUsers$ | async">
  Found matching user {{user.name}}
</div>

<div *ngIf="userService.matchingUsers$ | async as matchingUsers">
  <div *ngIf="!matchingUsers.length">
    Sorry, no matching users.
  </div>
</div>

等等。请注意,此as语法需要Angular 4。

这是Angular / observable / AngularFirebase方式。

答案 1 :(得分:0)

subscribe函数返回一个Subscription对象。

您正在分配FirebaseListObservable参考。 而是在分配后订阅,如果您需要重用observable。

this.user = this.afDb.list('/users',{

    query: {

        orderByChild: 'email',
        equalTo: this.email,
    },
    preserveSnapshot: true
})
this.user.subscribe(snapshots =>{

        let user_data = [];
        snapshots.forEach(snapshot=>{
            user_data.push(snapshot.val());
        });