Я лениво загружаю данные, используя фальшивый бэкэнд.Бэкэнд возвращает массив.Поскольку я хочу лениво загружать данные, я буферирую их каждые 100 записей.Событие, которое вызовет вызов для получения дополнительных данных, будет настраиваемым событием, но пока я тестирую его с помощью кнопки.
multiselect.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
export interface ProductCategory {
id: number;
name: string;
}
@Injectable({
providedIn: 'root'
})
export class MultiSelectService {
constructor(private http: HttpClient) { }
private readonly categorySubject = new BehaviorSubject(undefined);
readonly categories$ = this.categorySubject.asObservable();
// URL to web api - mocked. Categories is the object present in the mock server file
private categoriesUrl = 'api/categories';
/** GET heroes from the server */
getCategories(): void {
this.http.get<Array<ProductCategory>>(this.categoriesUrl, httpOptions)
.subscribe( data => {
data.map( category => this.categorySubject.next(category));
this.categorySubject.subscribe( xyz => console.log(xyz));
});
}
}
multiselect.component.ts
import { Component, AfterViewInit } from '@angular/core';
import { zip, Observable, fromEvent } from 'rxjs';
import { MultiSelectService, ProductCategory } from './multiselect.service';
import { bufferCount, startWith, map, scan } from 'rxjs/operators';
@Component({
selector: 'multiselect',
templateUrl: './multiselect.component.html',
styleUrls: ['./multiselect.component.scss']
})
export class MultiselectComponent implements AfterViewInit {
SLICE_SIZE = 100;
constructor(private data: MultiSelectService) { }
ngAfterViewInit() {
const loadMore$ = fromEvent(document.getElementsByTagName('button')[0], 'click');
this.data.getCategories(); // loads the data
zip(
this.data.categories$.pipe(bufferCount(this.SLICE_SIZE)),
loadMore$.pipe(startWith(0)),
).pipe(
map(results => results[0]),
scan((acc, chunk) => [...acc, ...chunk], []),
).subscribe({
next: v => console.log(v),
complete: () => console.log('complete'),
});
}
}
multiselect.component.html
<button>Fetch more results</button>
1) Количество элементов - 429, и я показываю их партиями по 100 элементов.После четырех кликов (4 х 100) последние 29 никогда не показываются.Чего мне не хватает, чтобы отобразить последние 29 элементов?Мне удалось проверить, что субъект выдал все значения.
2) Есть ли лучший способ достижения той же функциональности, которую я здесь разрабатываю?Я сопоставляю (это может быть цикл forEach) массив из-за того, что после запроса данных я получу только один элемент (массив) со всеми элементами (429).Это не позволит мне буферизовать элементы, если я захочу выполнить отложенную загрузку.
3) От меня требуется предоставить начальное значение для поведенияSubject, есть ли способ избежать этого?
Заранее спасибо!