尝试使用来自 Firebase 的流构建 obj 时出现 RxJS 操作错误

RxJS error of manipulations while trying to build obj with streams coming from Firebase

我正在尝试使用来自 Firebase 的多个流构建一个模板驱动的表单。 但我不断收到关于

的错误

Converting circular structure to JSONas soon as I use the| json pipe.

(这个错误我真的不懂)

而且我也很难用 RxJS 构建 object 我需要的方式。

我需要这样的东西来在视图中构建表单:

[
  {
    "name": "screens_size",
    "values": ["29-", "30-39", "40-49"]
  },
  {
    "name": "colors",
    "values": ["red", "yellow", "green"]
  }
]

如何从 firebase 的以下内容中获取类似上面的内容。 数据位于 Firebase 中的 2 个单独列表中。 它的存储方式如下:

{
  "nodes_filters": {
    "$id": {
      "screens_size": true,
      "colors": true
    }
  }
}

用于nodeService.getNodeFiltersGroups()

{
  "filters_values": {
    "screens_size": {
      "29-": true,
      "30-39": true,
      "40-49": true
    },
    "colors": {
      "red": true,
      "yellow": true,
      "green": true
    },
  }
}

用于nodeService.getFilterValues()

node.service.ts

import {Injectable} from "@angular/core";
import {AngularFireDatabase} from "angularfire2";

@Injectable()
export class NodeService {

  constructor(private db: AngularFireDatabase) {}

  getNodeFiltersGroups(nodeId) {
    return this.db.list('nodes_filters/' + nodeId);
  }

  getFilterValues(filterId, query = {}) {
    return this.db.list('filters_values/' + filterId, query);
  }

}

filters.component.ts

import {Component, OnInit, ViewChild} from '@angular/core';
import {Input} from "@angular/core/src/metadata/directives";
import {Observable} from "rxjs/Observable";
import {NodeService} from "../node.service";
import {FormGroup} from "@angular/forms";

@Component({
  selector: 'filters',
  templateUrl: './filters.component.html',
  styleUrls: ['./filters.component.scss']
})
export class FiltersComponent implements OnInit {

  public filterTypes$;
  public valuesFilter$;
  public filters = [];
  public filterValues;

  @Input() nodeId;
  @Input() currentFilters;

  constructor(private nodeService: NodeService) {}

  ngOnInit() {

    this.filterTypes$ = this.nodeService.getNodeFiltersGroups(this.nodeId)
      .map(c => c.map(y => ({"name": y.$key})))
      //  [{"name": "screens_size"}, {"name": "stores"}]

    const filterTypesArray = this.filterTypes$
      .map(x => x.map(y => y.name))
      //  ["screens_size", "stores"]


    this.valuesFilter$ = filterTypesArray
      .do(console.log) //  ["screens_size", "stores"]
      .flatMap(y => y.map(x => this.nodeService.getFilterValues(x, { query: { orderByValue: true, equalTo: 1 } })))
      .do(console.log) //  FirebaseListObservable {_isScalar: false, _ref: U}

  }

}

Edit2 添加了以下内容

filters.component.html

<h2>Filters</h2>

<form #filterForm="ngForm" novalidate>

  {{valuesFilter$ | async | json }}

</form>

我目前得到的所有这些线

EXCEPTION: Error in ./FiltersComponent class FiltersComponent - inline template:10:38 caused by: Converting circular structure to JSON

如果我删除 json 管道但我得到 [object Object]

,则此错误已修复

如果我尝试这样做

<h2>Filters</h2>


<form #filterForm="ngForm" novalidate>

  <ul>

    <li *ngFor="let v of valuesFilter$ | async">
      {{v}}
    </li>

  </ul>

</form>

我收到以下错误:

EXCEPTION: Error in ./FiltersComponent class FiltersComponent - inline template:7:8 caused by: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

所以我想我给它 object 而不是数组,但我不知道该怎么做。我迷失在我的 RxJS 部分。

过去 3 天我一直在研究这个问题。任何建议都会有用。如果有什么不清楚的地方,请告诉我,我会尽力澄清。

编辑 3:添加以下内容

有了 forkJoin 和@cartant 的解决方案,它好多了,我得到了以下结果 object:

[ 
  [ 
    { "$value": 1, "$key": "29-" }, 
    { "$value": 1, "$key": "30-39" }, 
    { "$value": 1, "$key": "40-49" }
  ], 
  [ 
    { "$value": 1, "$key": "red" }, 
    { "$value": 1, "$key": "yellow" } 
  ] 
]

但在视图中,我需要能够分辨出来自带过滤器的值。所以我需要这样的东西:

[ 
  {
    "name": "screens_size",
    "values": [ 
      { "$value": 1, "$key": "29-" }, 
      { "$value": 1, "$key": "30-39" }, 
      { "$value": 1, "$key": "40-49" }
    ]
  }, {
    "name": "colors",
    "values": [ 
      { "$value": 1, "$key": "red" }, 
      { "$value": 1, "$key": "yellow" } 
    ]
  }
]

obj 已经在 filterTypes$ 中构建了一些。

Edit1:更新标题

Edit2:添加 filters.component.html 文件和一些解释

Edit3:它适用于 forkJoin。在视图中添加有关所需对象的一些详细信息

您对 flatMap 的调用是 return 一个可观察值数组,因此:

this.valuesFilter$ = filterTypesArray
  .do(console.log) //  ["screens_size", "stores"]
  .flatMap(y => y.map(x => this.nodeService.getFilterValues(x, { query: { orderByValue: true, equalTo: 1 } })))
  .do(console.log) //  FirebaseListObservable {_isScalar: false, _ref: U}

影响类型为 Observable<FirebaseListObservable<any>> 的可观察对象,因为它是扁平化的数组。

当您使用 async 管道时,您会得到 FirebaseListObservable 作为结果,而当它被 json 管道接收时会出现 'circular structure' 错误。

如果你想将过滤器数组映射到过滤器值,你可以使用 forkJoin(它接受一个可观察值数组和 returns 一个发出最后值数组的可观察值从那些可观察到的):

this.valuesFilter$ = filterTypesArray
  .flatMap(types => Observable.forkJoin(
    types.map(type => this.nodeService.getFilterValues(type, {
      query: { orderByValue: true, equalTo: 1 }
    }).first())
  ))

请注意,使用了 first,因为传递给 forkJoin 的可观察对象必须完成。

对于return过滤器值数组以外的东西,可选的forkJoin选择器可用于组合过滤器名称和值:

this.valuesFilter$ = filterTypesArray
  .flatMap(types => Observable.forkJoin(
    types.map(type => this.nodeService.getFilterValues(type, {
      query: { orderByValue: true, equalTo: 1 }
    }).first()),
    (...results) => types.map((type, index) => ({ name: type, values: results[index] }))
  ));