AngularFire2查询列表获取子值

时间:2017-08-22 12:49:11

标签: javascript angular firebase firebase-realtime-database angularfire2

我有以下数据结构:

{
 "users" : {
    "AXLKSD9ASLKDJJ0991" : {
      "authType" : "ap1",
      "enabled" : true,
      "color" : "red"
    },
    "A778ASDUASDJ8AS8DA" : {
      "authType" : "ap1",
      "enabled" : true,
      "color" : "blue"
    },
    "ASD88ASD8ASD8HAS8D" : {
      "authType" : "ap2",
      "enabled" : true,
      "color" : "red"
    }
  }
}

我创建了一个专门用于Firebase的服务,该服务具有以下方法。这成功地将用户返回到我的组件中:

firebase.service.ts:

userList: FirebaseListObservable<any[]>;

getUsersByAuthType(authType: string) {
  return this.userList = this.afDb.list('/users', {
    preserveSnapshot: true,
    query: {
        orderByChild: 'authProvider',
        equalTo: authType
    }
  });
}

admin.component.ts:

import { Component, OnInit } from '@angular/core';

import { FirebaseService } from '../services/firebase.service';

@Component({
  selector: 'app-administration',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdministrationComponent implements OnInit {
  usersData: any;

  constructor(
      private firebaseService: FirebaseService
  ) { }

  ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1');
  }

}

admin.component.html:

<h2>test 1</h2>
<ul *ngFor="let user of (usersData | async)">
<li>{{ user.enabled }}</li>
</ul>

<br /><br /><br />

<h2>test 2</h2>
{{ usersData | async | json }}

<br /><br /><br />

<h2>test 3</h2>
<ul *ngFor="let user of (usersData | async)">
<li>{{ user.key }}</li>
</ul>

&#34;测试1&#34;没有显示任何东西..

&#34;测试2&#34;显示整个返回的json对象:

{ "authType" : "ap1", "enabled" : true, "color" : "red" }, { "authType" : "ap1", "enabled" : true, "color" : "blue" }

&#34;测试3&#34;向我展示了钥匙。

我尝试过其他一些方法但没有成功。参考文档表明我正在做的事情是好的

https://github.com/angular/angularfire2/blob/master/docs/4-querying-lists.md

想法?

更新

我还在admin.component.html中添加了以下内容:

<br /><br /><br />

<h2>test 4</h2>
<ul *ngFor="let user of (usersData | async)">
<li>{{ (user | json) }}</li>
</ul>

这也在渲染页面中产生了以下输出:

  • {&#34; authType&#34; :&#34; ap1&#34;,&#34;启用&#34; :true,&#34; color&#34; :&#34;红色&#34; }
  • {&#34; authType&#34; :&#34; ap1&#34;,&#34;启用&#34; :true,&#34; color&#34; :&#34;蓝色&#34; }

更新#2

总结一些建议......

<ul *ngFor="let user of (usersData | async)">
<li>{{ user[user.key].enabled }}</li>
</ul>

<ul *ngFor="let user of (usersData | async)">
<li>{{ user[user.key]?.enabled }}</li>
</ul>

这些都没有返回任何内容,也没有记录任何错误。

以下是有趣的:

<ul *ngFor="let user of (usersData | async)">
<li>{{ user.val }}</li>
</ul>

这在组件中呈现了以下内容:

  • function(){(0, validation.validateArgCount)(&#39; DataSnapshot.val&#39;,0,0,arguments.length); return this.node .val(); }
  • function(){(0, validation.validateArgCount)(&#39; DataSnapshot.val&#39;,0,0,arguments.length); return this.node .val(); }

更新#3

建议将呼叫映射到我的firebase服务,如下所示:

ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1')
                               .map(res => res.json());
}

然后按如下所示更新我的组件视图:

<ul *ngFor="let user of (usersData | async)">
  <li>{{ user?.enabled }}</li>
</ul>

这导致以下错误:

ERROR TypeError: res.json is not a function
    at MapSubscriber.project (administration.component.ts:26)
    at MapSubscriber.webpackJsonp.../../../../rxjs/operator/map.js.MapSubscriber._next (map.js:77)
    at MapSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
    at SwitchMapSubscriber.webpackJsonp.../../../../rxjs/operator/switchMap.js.SwitchMapSubscriber.notifyNext (switchMap.js:124)
    at InnerSubscriber.webpackJsonp.../../../../rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
    at InnerSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
    at Notification.webpackJsonp.../../../../rxjs/Notification.js.Notification.observe (Notification.js:32)
    at QueueAction.webpackJsonp.../../../../rxjs/operator/observeOn.js.ObserveOnSubscriber.dispatch (observeOn.js:87)
    at QueueAction.webpackJsonp.../../../../rxjs/scheduler/AsyncAction.js.AsyncAction._execute (AsyncAction.js:111)
    at QueueAction.webpackJsonp.../../../../rxjs/scheduler/QueueAction.js.QueueAction.execute (QueueAction.js:33)

我还尝试将整个usersData转储出来:

<h3>The whole lot</h3>
{{ usersData }}

渲染:

[object Object]

同样值得分享一下,当我在console.log中返回firebase服务的内容时,它会返回:

[DataSnapshot,DataSnapshot]

如果我展开它,你可以清楚地看到两个数组元素及其键属性,但是子节点不能立即可见但深埋在结构中:

  • [DataSnapshot,DataSnapshot]
    • 0:DataSnapshot
      • index_:PathIndex
      • key:&#34; 23123123123123&#34;
      • node_:ChildrenNode
        • comparator_:function NAME_COMPARATOR(left,right)
        • root_:LLRBNode
          • color:false
          • key:&#34;已启用&#34;
          • 左:LLRBNode
          • 右:LLRBNode
          • value:LeafNode
            • lazyHash_:null
            • priorityNode_:ChildrenNode
            • value_:&#34; true&#34;
          • proto :对象
        • proto :对象
      • 参考:参考
      • ref_:参考
      • proto :对象
        • 1:DataSnapshot
      • 长度:2
        • proto :数组(0)

经过一些在线阅读后,似乎我需要创建一个自定义管道进行转换,但我不知道如何去做。我所看到的例子,首先是错误,不能编译,但也不清楚它是如何工作的。

我是否在正确的轨道上?

我仍然坚持为什么&#34;测试4&#34;我完全按照我的期望和需要呈现,我只是无法通过属性名称访问它(例如,启用,authType等)?

更新#4

我已将admin.component.html更新为:

<h3>Test 5</h3>
<ng-container *ngIf="usersData != null && usersData.length !== 0">
  <ul *ngFor="let user of usersData">
    <li>{{ user?.enabled }}</li>
  </ul>
</ng-container>

我已经更新了admin.component.ts ngOnInit,如下所示,并从@ angular / core导入了markForCheck:

  ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1')
      .map(res => res.json())
      .subscribe(result => {
        this.usersData = result;
        this.ref.markForCheck();
      });
  }

控制台提供以下见解:

AdminComponent.html:32 ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
    at NgForOf.webpackJsonp.../../../common/@angular/common.es5.js.NgForOf.ngOnChanges (common.es5.js:1659)
    at checkAndUpdateDirectiveInline (core.es5.js:10831)
    at checkAndUpdateNodeInline (core.es5.js:12330)
    at checkAndUpdateNode (core.es5.js:12269)
    at debugCheckAndUpdateNode (core.es5.js:13130)
    at debugCheckDirectivesFn (core.es5.js:13071)
    at Object.eval [as updateDirectives] (AdministrationComponent.html:32)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13056)
    at checkAndUpdateView (core.es5.js:12236)
    at callViewAction (core.es5.js:12601)

core.es5.js:1020 ERROR TypeError: res.json is not a function
    at MapSubscriber.project (administration.component.ts:30)
    at MapSubscriber.webpackJsonp.../../../../rxjs/operator/map.js.MapSubscriber._next (map.js:77)
    at MapSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
    at SwitchMapSubscriber.webpackJsonp.../../../../rxjs/operator/switchMap.js.SwitchMapSubscriber.notifyNext (switchMap.js:124)
    at InnerSubscriber.webpackJsonp.../../../../rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
    at InnerSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
    at Notification.webpackJsonp.../../../../rxjs/Notification.js.Notification.observe (Notification.js:32)
    at QueueAction.webpackJsonp.../../../../rxjs/operator/observeOn.js.ObserveOnSubscriber.dispatch (observeOn.js:87)
    at QueueAction.webpackJsonp.../../../../rxjs/scheduler/AsyncAction.js.AsyncAction._execute (AsyncAction.js:111)
    at QueueAction.webpackJsonp.../../../../rxjs/scheduler/QueueAction.js.QueueAction.execute (QueueAction.js:33)

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

试试这个:

user[user.key].enabled

OR

问题在于结果的类型。尝试在调用subscribe或“async”之前映射结果:

ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1')
                               .map(res => res.json());
}

你不需要那个| JSON

你现在可以去:

<ul *ngFor="let user of (usersData | async)">
     <li>{{ user?.enabled }}</li>
</ul>

使用sync而不是async:

users: any;

constructor(private ref: ChangeDetectorRef) {}

ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1')
                    .map(res => res.json()).subscribe(result => { 
                       users = result.users; 
                       this.ref.markForCheck();
                    });
}


<ng-container *ngIf="user != null && user.length !== 0">
   <ul *ngFor="let user of user">
        <li>{{ user?.enabled }}</li>
   </ul>
</ng-container>

您现在可以在订阅中设置调试器,以显示您正在接收的数据类型。实际上,它必须工作。

答案 1 :(得分:0)

所以问题归结为preserveSnapshot选项。

原始firebase.service.ts snippit:

userList: FirebaseListObservable<any[]>;

getUsersByAuthType(authType: string) {
  return this.userList = this.afDb.list('/users', {
    preserveSnapshot: true,
    query: {
        orderByChild: 'authProvider',
        equalTo: authType
    }
  });
}

我需要放弃 preserveSnapshot:true 并将其设置为 false

admin.component.ts(无变化):

import { Component, OnInit } from '@angular/core';

import { FirebaseService } from '../services/firebase.service';

@Component({
  selector: 'app-administration',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdministrationComponent implements OnInit {
  usersData: any;

  constructor(
      private firebaseService: FirebaseService
  ) { }

  ngOnInit() {
    this.usersData = this.firebaseService.getUsersByAuthType('ap1');
  }
}

admin.component.html(无更改):

<ul *ngFor="let user of (usersData | async)">
<li>{{ user.enabled }}</li>
</ul>

组件按预期正确呈现。不确定 preserveSnapshot:true 是组件html的问题,但它确实存在。

如果有人知道为什么会这样,我很想知道。