#arrays #json #angular #typescript
#массивы #json #угловой #typescript
Вопрос:
Я работаю над проектом angular, и моя задача — отфильтровать огромный файл на основе ключа «_type», который может принимать разные значения. Прямо сейчас я хочу сначала отфильтровать _type = «COMPETITION».
Моя модель определена в файле competition.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"
}
Вот мой класс обслуживания, в котором я пытаюсь реализовать это:
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;
});
}
}
Я прикрепил снимок результата на моей консоли, который на самом деле не делает того, чего я действительно хочу достичь.
Комментарии:
1. Не могли бы вы, пожалуйста, включить код, в котором содержится ваш вызов фильтра?
2. Привет, Дервис, я включил его, вы можете посмотреть, когда будете свободны, спасибо за ваше время и помощь!
Ответ №1:
Я вижу здесь несколько проблем
-
Вы пытаетесь получить асинхронную переменную
this.loadedCompetitions
синхронно. Это невозможно. Доступ ко всем асинхронным переменным должен осуществляться асинхронно. Вы могли бы использовать RxJSReplaySubject
multicast observable с буфером 1 для хранения и выдачи последнего значения. -
Вам не нужно вручную перебирать каждый элемент массива и создавать новый массив со
_type === 'COMPETITION'
свойством. Вы могли бы использовать функцию Arrayfilter
для фильтрации объектов на основе условия.
...
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
);
}
}
- Теперь вам нужно подписаться на
loadedCompetitions
переменную, чтобы получать от нее уведомления. Я использовалtakeWhile
оператор RxJS с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
}
}
Комментарии:
1. @UbunTube: Я не могу лично просмотреть ваши файлы. Попробуйте вышеупомянутое предложение, и если оно не сработает, вы можете попытаться найти решение, просмотрев другие ответы или опубликовав новый вопрос.