Я новичок в rxjs, и я разрабатываю компонент углового множественного выбора, который должен отображать длинный список значений (более 500).Я рендеринг списка на основе UL, я перебираю наблюдаемые, которые будут визуализировать LI.Я думаю о своих возможностях избежать влияния на производительность, отрисовывая все элементы одновременно.Но я не знаю, возможно ли это или нет, и если это возможно, какой оператор лучше всего использовать.
Предлагаемое решение:
- При инициализации я загружаю все данные в Observable.(src), я возьму из него 100 элементов и поместу их в целевую наблюдаемую область (ту, которая будет использоваться для визуализации списка)
Каждый раз, когда пользователь достигает концаlist (запускается событие scrollEnd) Я буду загружать еще 100 элементов, пока в src не будет больше значений.
Будет сгенерировано излучение новых значений в целевой наблюдаемой.по событию scrollEnd.
Найдите мой код ниже, мне все еще нужно реализовать предложенное решение, но я застрял в этой точке.
РЕДАКТИРОВАТЬ: я внедряю решение @martin, но все еще не могу заставить его работать в моем коде.Моим первым шагом было скопировать его в коде, чтобы получить записанные значения, но наблюдаемое завершается немедленно, без создания каких-либо значений.Вместо того, чтобы вызвать событие, я добавил тему.Каждый раз, когда выводится scrollindEnd, я добавляю новое значение в тему.Шаблон был изменен для поддержки этого.
multiselect.component.ts
import { Component, AfterViewInit } from '@angular/core';
import { zip, Observable, fromEvent, range } from 'rxjs';
import { map, bufferCount, startWith, scan } from 'rxjs/operators';
import { MultiSelectService, ProductCategory } from './multiselect.service';
@Component({
selector: 'multiselect',
templateUrl: './multiselect.component.html',
styleUrls: ['./multiselect.component.scss']
})
export class MultiselectComponent implements AfterViewInit {
SLICE_SIZE = 100;
loadMore$: Observable<Event>;
numbers$ = range(450);
constructor() {}
ngAfterViewInit() {
this.loadMore$ = fromEvent(document.getElementsByTagName('button')[0], 'click');
zip(
this.numbers$.pipe(bufferCount(this.SLICE_SIZE)),
this.loadMore$.pipe(),
).pipe(
map(results => console.log(results)),
).subscribe({
next: v => console.log(v),
complete: () => console.log('complete ...'),
});
}
}
multiselect.component.html
<form action="#" class="multiselect-form">
<h3>Categories</h3>
<input type="text" placeholder="Search..." class="multiselect-form--search" tabindex="0"/>
<multiselect-list [categories]="categories$ | async" (scrollingFinished)="lazySubject.next($event)">
</multiselect-list>
<button class="btn-primary--large">Proceed</button>
</form>
multiselect-list.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'multiselect-list',
templateUrl: './multiselect-list.component.html'
})
export class MultiselectListComponent {
@Output() scrollingFinished = new EventEmitter<any>();
@Input() categories: Array<string> = [];
constructor() {}
onScrollingFinished() {
this.scrollingFinished.emit(null);
}
}
multiselect-list.component.html
<ul class="multiselect-list" (scrollingFinished)="onScrollingFinished($event)">
<li *ngFor="let category of categories; let idx=index" scrollTracker class="multiselect-list--option">
<input type="checkbox" id="{{ category }}" tabindex="{{ idx + 1 }}"/>
<label for="{{ category }}">{{ category }}</label>
</li>
</ul>
ПРИМЕЧАНИЕ: Событие scrollingFinished инициируется директивой scrollTracker, которая содержит логику отслеживания.Я передаю событие из списка множественного выбора в компонент множественного выбора.
Заранее спасибо!