我正在尝试在我的离子型角度应用程序中实现无限滚动。对此我是新手,我需要一些专家意见。问题是more()函数在第一次滚动事件发生时起作用,但是在尝试获取第二组文档时会陷入无限循环。这是代码,我包括了组件和html的图片以及完整的分页服务。
Component.ts:
ngOnInit() {
this.page.init('Documents', 'Name', { reverse: false, prepend: false })
scrollHandler(e) {
if (e === 'bottom') {
this.page.more()
}
}
模板html:
<ion-infinite-scroll threshold="100px" (ionInfinite)="this.page.more($event)">
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more data...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
pagination-service.ts:
import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { tap, scan, take} from 'rxjs/operators';
// Options to reproduce firestore queries consistently
interface QueryConfig {
path: string, // path to collection
field: string, // field to orderBy
limit?: number, // limit per query
reverse?: boolean, // reverse order?
prepend?: boolean // prepend to source?
}
@Injectable()
export class PaginationService {
// Source data
private _done = new BehaviorSubject(false);
private _loading = new BehaviorSubject(false);
private _data = new BehaviorSubject([]);
private query: QueryConfig;
// Observable data
data: Observable<any>;
done: Observable<boolean> = this._done.asObservable();
loading: Observable<boolean> = this._loading.asObservable();
constructor( private afs: AngularFirestore ) { }
// Initial query sets options and defines the Observable
init(path, field, opts?) {
this.query = {
path,
field,
limit: 10,
reverse: false,
prepend: false,
...opts
}
const first = this.afs.collection(this.query.path, ref => {
return ref
.orderBy(this.query.field, this.query.reverse ? 'desc' : 'asc')
.where('Active', '==', 'Y')
.limit(this.query.limit)
})
this.mapAndUpdate(first)
// Create the observable array for consumption in components
this.data = this._data.asObservable()
.pipe(scan( (acc, val) => {
return this.query.prepend ? val.concat(acc) : acc.concat(val)
}))
}
// more() Retrieves additional data from firestore
// This works the first time but not the second time
more() {
const cursor = this.getCursor()
const more = this.afs.collection(this.query.path, ref => {
return ref
.orderBy(this.query.field, this.query.reverse ? 'desc' : 'asc')
.limit(this.query.limit)
.startAfter(cursor)
})
this.mapAndUpdate(more)
}
// Determines the doc snapshot to paginate query
private getCursor() {
const current = this._data.value
if (current.length) {
return this.query.prepend ? current[0].doc : current[current.length - 1].doc
}
return null
}
// Maps the snapshot to usable format the updates source
private mapAndUpdate(col: AngularFirestoreCollection<any>) {
if (this._done.value || this._loading.value) { return };
// loading
this._loading.next(true)
// Map snapshot with doc ref (needed for cursor)
return col.snapshotChanges()
.pipe(tap(arr => {
let values = arr.map(snap => {
const data = snap.payload.doc.data()
const doc = snap.payload.doc
return { ...data, doc }
})
// If prepending, reverse array
values = this.query.prepend ? values.reverse() : values
// update source with new values, done loading
this._data.next(values)
this._loading.next(false)
// no more values, mark done
if (!values.length) {
this._done.next(true)
}
}))
.pipe(take(1))
.subscribe()
}
// Reset the page
reset() {
this._data.next([])
this._done.next(false)
}
}
答案 0 :(得分:0)
当用户达到定义的距离时,将调用分配给ionInfinite事件的表达式。此表达式完成所有任务后,应在无限滚动实例上调用complete()方法。
就您而言,您尚未处理事件,只是通过了...
this.page.more($event)
如下更改模板html:
<ion-infinite-scroll threshold="100px" (ionInfinite)="findNext($event)">
在Component.ts中添加方法:
async findNext($event) {
setTimeout(async () => {
await this.page.more();
$event.target.complete();
}, 500);
}