【问题标题】:Merge two Observables and pass into dataSource as a single Observable for Angular material table合并两个 Observable 并作为 Angular 材料表的单个 Observable 传递到 dataSource
【发布时间】:2020-09-29 12:29:31
【问题描述】:

我是 Web 开发的新手,过去几天一直被这个问题困扰,如果社区可以在这里帮助我,将不胜感激

我想合并来自 firebase 数据库的两个 observables,我想同时加入它们,即 第一个 observable 的 3 行与另一个 observable 的 3 行映射。我想将此 observable 用于 Angular Mat Table 的数据源。并从此处的两个可观察对象中提取字段

这是 Component.ts

import { Component, OnInit } from '@angular/core';
import { ProductService } from 'src/app/product.service';
import { Observable, observable } from 'rxjs';
import "rxjs/add/observable/zip";
import "rxjs/add/observable/forkJoin";

@Component({
  selector: 'app-admin-products',
  templateUrl: './admin-products.component.html',
  styleUrls: ['./admin-products.component.css']
})
export class AdminProductsComponent implements OnInit {
  products$:Observable<any[]>
  productsKey$:Observable<any[]>
  finalProduct$
  list:[]

  constructor(private productService:ProductService) {
    this.products$ = this.productService.getAll().valueChanges();

    this.productsKey$ = this.productService.getAll().snapshotChanges();


    //this.finalProduct$ = (this.products$).pipe(merge(this.productsKey$));

  }

   displayedColumns = ['title','price','edit'];
  // dataSource = this.products$

  ngOnInit(): void {

  }



}

这是service.ts

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

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  constructor(private db:AngularFireDatabase) { }

  create(product){
 console.log(product)
   return this.db.list('/products').push(product);

  }

  getAll(){
    return this.db.list('/products')
  }
}

这是最终的 HTML 标记



<p style="padding: 50px;">
    <button mat-flat-button color="primary" routerLink="/admin/products/new" > Add New Product</button>
</p>




<mat-table  [dataSource]="finalProduct$ | async" class="mat-elevation-z8">
    <!-- Position Column -->
    <ng-container matColumnDef="title">
      <mat-header-cell *matHeaderCellDef> Title </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{ element.title }} </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="price">
      <mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.price}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="edit">
        <mat-header-cell *matHeaderCellDef>  </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{element | json}} </mat-cell>
      </ng-container>


    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>

第一个 Observable products$ 有这种格式的数据

{category: "bread", imageUrl: "https://pixabay.com/photos/bread-food-isolated-croissant-loaf-4592483/", price: 50, title: "Freshly Baked Bread"}

第二个可观察的 productsKey$ 具有这种格式的数据

{payload: DataSnapshot, type: "value", prevKey: null, key: "-M9HwZl_WYfgTchxanrb"}

我希望从这些 observables 中提取价格、标题和键值并将它们显示在一个表格中。

【问题讨论】:

    标签: html angular typescript rxjs observable


    【解决方案1】:

    我建议使用zip,它完全符合您的要求,即合并 2 个 observables。

    ngOnInit(): void {
      zip(this.products$, this.productsKey$).pipe(
        map(reponse => { return {...reponse[0], ...response[1]}})
      ).subscribe(
        reponse => {
          this.dataSource = reponse;
        });
    

    您也可以将combineLatest 用作Michael 的建议,稍作修改。将map(reponse =&gt; [...reponse[0], ...response[1]]) 更改为map(reponse =&gt; { return {...reponse[0], ...response[1]}})

    【讨论】:

    • 嗨 KoosKoos,非常感谢。这就像一个魅力
    • 谢谢,@mohitnirwan。很高兴,我能够提供帮助:)
    【解决方案2】:

    如果 observables 彼此独立,您可以使用 RxJS combineLatest() 函数来组合多个 observables。

    displayedColumns = ['title', 'price', 'edit'];
    
    constructor(private productService: ProductService) {
      this.products$ = this.productService.getAll().valueChanges();
      this.productsKey$ = this.productService.getAll().snapshotChanges();
    }
    
    ngOnInit(): void {
      combineLatest(this.products$, this.productsKey$).pipe(
        take(1),     // <-- remove it if the data stream needs to persist
        map(reponse => [...reponse[0], ...response[1]])
      ).subscribe(
        reponse => {
          this.dataSource = reponse;
        }
      );
    }
    

    【讨论】:

    • 您好,感谢您这么快的回答,它似乎正在工作,但有点打嗝。输出不是所需的。 imgur.com/oAjlYjK 。你能帮我把输出重新排列成相同的行而不是新的行吗@michael-d
    • @mohitnirwan:问题出在这一行:reponse =&gt; [...reponse[0], ...response[1]]。应修改对象结构以满足您的要求。
    • 是的,想通了。非常感谢你
    猜你喜欢
    • 1970-01-01
    • 2021-02-02
    • 2017-08-04
    • 2011-10-29
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多