简体   繁体   English

如何过滤可观察的包装 json 文件响应?

[英]How to filter an observable wrapped json file response?

I am working on a angular project and my task is to filter a huge file based on the "_type" key which can take different values.我正在处理一个 angular 项目,我的任务是根据可以采用不同值的“_type”键过滤一个大文件。 Right now I want to first filter _type = "COMPETITION".现在我想先过滤 _type = "COMPETITION"。

My model is defined in a competition.model.ts file which looks like this:我的模型是在一个如下所示的竞争.model.ts 文件中定义的:

export interface Competition {
  product: { active: true };
  schemaVersion: number;      // 2,
  status: string;             // PUBLISHED",
  comp: string;               // "4fc16b10-b8b4-4a99-b9f1-842f0d8b8413",
  _createdDate: number;       // 1594249198,
  discipline: string;         // "TRAP [ACTA]",
  categories: any;            // ["OPEN", "LADIES", "JUNIOR", "VETERAN", "CLAYS_ONLY"],
  host: string;               // "2",
  changeSet: number;          // 257,
  sync: number;               // 155,
  seq: number;                // 120,
  id: string;                 // "4fc16b10-b8b4-4a99-b9f1-842f0d8b8413",
  _type: string;              // "COMPETITION",
  when: number;               // 1597154400,
  title: string;              // "ACTA Self Nom Test"
}

Here is a my service class where I am trying to implement this:这是我正在尝试实现的服务类:

import { Injectable, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/Operators';
import { Competition } from '../interfaces/competition.model';

@Injectable ({providedIn: 'root'})

export class CompetitionListService {

  private loadedCompetitions: Competition[];
  private url = '../../assets/data/program1.json';

  constructor(private http: HttpClient) {}


  public getCompetitions(): Competition[] { return this.loadedCompetitions; }

  public fetchCompetition(){
    return this.http
    .get<Competition[]>(this.url)
      .pipe(
        map( (responseData) => {
          const competitionsArray = [];
          for (const key in responseData ) { // responseData is an object
            if (responseData.hasOwnProperty(key)) {
              // get the_type property
              // if ( key.valueOf() === 'COMPETITION') {
                competitionsArray.push(
                 // responseData[key]._createdDate,
                 responseData[key]._createdDate,
                  responseData[key]._type,
                  responseData[key].categories,
                  responseData[key].changeSet,
                  responseData[key].comp,
                  responseData[key].discipline,
                  responseData[key].host,
                  responseData[key].id,
                  responseData[key].product,
                  responseData[key].schemaVersion,
                  responseData[key].seq,
                  responseData[key].status
                );
            }

          }
          console.log(competitionsArray);
          return competitionsArray;
        })
      )
      .subscribe(competitions => {
          console.log(competitions);
          this.loadedCompetitions = competitions;
      });
  }
}

I attached the snapshot of the result on my console, which doesn't really do what I really want to achieve.我在我的控制台上附加了结果的快照,这并没有真正实现我真正想要实现的目标。

代码结果的屏幕截图

I see multiple issues here我在这里看到多个问题

  1. You're trying to fetch the asynchronous variable this.loadedCompetitions synchronously.您正在尝试同步获取异步变量this.loadedCompetitions It is not possible.这不可能。 All async variables should be accessed asynchronously.所有异步变量都应该异步访问。 You could use RxJS ReplaySubject multicast observable with buffer 1 to hold and emit the last value.您可以使用带有缓冲区 1 的 RxJS ReplaySubject多播可观察对象来保存和发出最后一个值。

  2. You don't to manually loop through each item of the array and create a new array with the _type === 'COMPETITION' property.您不必手动遍历数组的每个项目并使用_type === 'COMPETITION'属性创建一个新数组。 You could use Array filter function to filter out the objects based on a condition.您可以使用数组filter功能根据条件过滤掉对象。

...
import { Observable, ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable ({providedIn: 'root'})
export class CompetitionListService {
  private loadedCompetitions: ReplaySubject<Competition[]> = new ReplaySubject<Competition[]>(1);
  private url = '../../assets/data/program1.json';

  constructor(private http: HttpClient) {
    this.fetchCompetition();      // <-- triggers the request and pushes value to `loadedCompetitions`
  }

  public getCompetitions(): Observable<Competition[]> { 
    return this.loadedCompetitions.asObservable(); 
  }

  public fetchCompetition() {        // return nothing here
    this.http.get<Competition[]>(this.url).pipe(
      map(res => res.filter(item => item['_type'] !== 'COMPETITION'))
    ).subscribe(
      res => this.loadedCompetitions.next(res),
      err => console.log(err)           // <-- handle error
    );
  }
}
  1. Now you need to subscribe to loadedCompetitions variable to obtain notifications from it.现在您需要订阅loadedCompetitions变量以从中获取通知。 I've used RxJS takeWhile operator with Subject to close any open subscriptions in the ngOnDestroy hook of the component.我已经使用 RxJS takeWhile运算符和Subject来关闭组件的ngOnDestroy钩子中的任何打开的订阅。
...
import { Observable, Subject } from 'rxjs';
import { takeWhile } from 'rxjs/operators';

export class SomeComponent implements OnInit, OnDestroy {
  private close$ = new Subject<any>();    // <-- use to close open subscriptions

  constructor(private competitionListService: CompetitionListService) { }

  ngOnInit() {
    this.competitionListService.loadedCompetitions.pipe(
      takeWhile(this.close$)
    ).subscribe(
      res => {
        console.log(res);
        // other statements that depend on `res`
      }
    );
  }

  ngOnDestroy() {
    this.close$.next();     // <-- close open subscriptions
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM