У меня проблемы с оператором shareReplay
, потому что, вероятно, я не понял, как это работает на самом деле.
Я создаю спортивное приложение, которое показывает каждое спортивное событие в ближайшие 6 дней с сегодняшнего дня. ,API (который я не могу изменить) показывает каждое событие, запланированное для одного вида спорта, поэтому мне нужно создать фильтр, чтобы показывать только события, относящиеся к определенному дню.
Это служба, которая получает события из APIв соответствии с прошедшим днем. В качестве примера я показываю только две спортивные категории:
event-service.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, from } from 'rxjs';
import { DateService } from './date-service.service'
import { map, shareReplay } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class EventService {
private NBA_CODE = Constants.SPORT_CODE('NBA');
private SOCCER_CODE = Constants.SPORT_CODE('SOCCER');
private nbaObservable$ : Observable<any>;
private soccerObservable$ : Observable<any>;
req_day: any;
constructor(
private httpClient : HttpClient,
private dateService: DateService
) { }
getEvents(sport: string, day: string) : Observable<any> {
let url = //api url
this.req_day = this.dateService.getDates(day);
//getting Moment's requested day object from service
let offset = moment().utcOffset(); //calculating local offset
switch (sport) {
case 'NBA':
if(!this.nbaObservable$) {
this.nbaObservable$ = this.httpClient.get<any>(url)
.pipe(
map((data) => {
let data_filtered = this.filter(data);
return data_filtered
}),
shareReplay(1)
);
}
return this.nbaObservable$;
break;
case 'SOCCER':
if(!this.soccerObservable$) {
this.soccerObservable$ = this.httpClient.get<any>(url)
.pipe(
map((data) => {
let data_filtered = this.filter(data);
return data_filtered
}),
shareReplay(1)
);
}
return this.soccerObservable$;
break;
}
}
filter(data) {
if(!(data.events) || data.events.length == undefined || data.events.length == 0) {
return []; //data is empty or undefined
} else {
for (let i=0; i<data.events.length; i++) {
// start time UTC = moment.utc(data.events[i].startTime)
let startTime = moment.utc(data.events[i].startTime)._d
// if req_day is not the same of event day, remove it
if(!(this.req_day.isSame(startTime, 'day'))) {
data['events'].splice(i,1);
i--;
} else {
data['events'][i]['startTimeLocale'] = moment.utc(data.events[i].startTime)._d;
}
}
}
return data;
}
}
это component-details.ts , который отображает данные:
import { Component, OnInit } from '@angular/core';
import { EventService } from '../../services/event-service.service';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-odds-details',
templateUrl: './odds-details.component.html',
styleUrls: ['./odds-details.component.scss'],
})
export class OddsDetails implements OnInit, OnDestroy {
sub: any;
categories: any;
constructor(
private eventService: EventService,
private route: ActivatedRoute,
) { }
ngOnInit() {
this.setCategories();
this.getOdds();
}
setCategories() {
this.categories = [
{
apiCall: 'NBA',
//other data related to apiCall (icon url, events data...)
},
{
apiCall: 'SOCCER',
//...
}
]
}
getEvents() {
this.sub = this.route
.data
.subscribe(
(data) => {
var day = data.day;
for (let i=0; i<this.categories.length; i++) {
this.eventService.getEvents(this.categories[i]['apiCall'], day)
.subscribe((data) => {
if(data.events && data.events.length >= 1) {
this.categories[i]['events'] = data.events;
} else {
this.categories[i]['events'] = [];
}
})
}
})
}
}
наконец, это component.html шаблон:
<ion-content scrollable>
<ion-grid>
<div *ngFor="let p of categories">
<ion-row *ngIf="p?.events">
<ion-col size="12">
<ion-item (click) = "p.open = !p.open">
<ion-icon [src]="p.url" color="dark">
</ion-icon>
<ion-label>
{{p.title}}
</ion-label>
<ion-icon name="arrow-dropright" *ngIf="!p.open"></ion-icon>
<ion-icon name="arrow-dropdown* ngIf="p.open"></ion-icon>
</ion-item>
</ion-col>
<ion-row *ngFor="let event of p?.events">
<div *ngIf="p.open">
<ion-col size="12">
<div>
{{event?.description}}
</div>
</ion-col>
<ion-col size="12">
<div>
{{event?.startTimeLocale}}
</div>
</ion-col>
</div>
</ion-row>
</ion-row>
</div>
</ion-grid>
</ion-content>
Я думал, что этобыло бы лучше использовать только один компонент для хранения навигации по датам, а другой - для отображения подробностей событий для каждого дня, поэтому event-details.component находится внутри event.component , и эточто я получаю:
Он работает без оператора shareReplay
(даже если загрузка происходит каждый раз, когда я выбираю день, потому что он каждый раз вызывает службу),но если я использую его, приложение вылетает или показывает только значения с первого дня длякаждый день я выбираю.
Как правильно использовать его в этом контексте для извлечения данных определенного дня и вида спорта только один раз и немедленно возвращать эти данные при последующем запросе? Кроме того,как я могу воспроизвести результаты только за один день (так как завтра запросы будут другими)?
Спасибо