Firebase: InfiniteScroll & FirebaseListObservable

Hello,

I’m trying to do an ion-infinite-scroll with a FirebaseListObservable.
For this i have an Rx Subject in the query :

@Injectable()
export class Objects {

	public objects: FirebaseListObservable<any[]>;
	public nbObjects: Subject<any>;
	public cpt: number;

	constructor(public af: AngularFire, public platform: Platform) {
		this.cpt = 20;
		this.nbObjects = new Subject();
		this.events = this.af.database.list('/objects', {
			query: {
				orderByChild: 'timestamp',
				startAt: Date.now()/1000, 
				limitToFirst: this.nbObjects
			}
		});
		this.platform.ready().then(() => {
		  this.nbObjects.next(this.cpt);
		});
	}
	
	loadMoreObjects() : void {
		this.cpt += 20;
		this.nbObjects.next(this.cpt); 
	}

}

With this, i have the following function in my component :

	doInfinite(infiniteScroll) {
		this.objects.loadMoreObjects();
		setTimeout(() => {
			infiniteScroll.complete();
		}, 3000);
	}

But my problem is : How can i remove the timeout to listen updates on my FirebaseListObservable Object ? And is it possible to tell when there is no more objects to load ?
Is this a right approach ?

1 Like

And one last question :
When using the following code :

loadEvents(path: string) : void {
	this.objects = this.af.database
			.list(path, {
				query: {
					orderByChild: 'timestamp',
					startAt: Date.now()/1000, 
					limitToFirst: this.nbObjects
				}
			})
			.mergeMap((events) => {
				return Observable.forkJoin(
					events.map((event) => {
						return this.af.database.object('/objects/'+event.$key).first();
					}),
					(...values) => {
						events.forEach((event, index) => { event.event = values[index]; });
						return events;
					}
				);
			}) as FirebaseListObservable<any[]>;

	setTimeout(() => { this.nbObjects.next(20); }, 200);
}

I have to put this.nbObjects.next(20); in a timeout and if i don’t, my html page won’t display any object of this.objects.
What’s wrong ? I cannot figure where the problem is exactly :confused:

Okay, I found a solution to listen at my FirebaseListObservable changes. But still have question.

I declare isLoading : Subject = new Subject(); and at the end of my forkJoin, just before return events; I add this.isLoading.next();.
Then, my ionInfiniteList function look like this :

doInfinite(infiniteScroll) {
	this.provider.isLoading
		.first()
		.subscribe((x) => {
			infiniteScroll.complete();
		});
	this.provider.loadMoreObjects();
}

I listen to one emit of my Observable isLoading, and then i complete infiniteScroll because i know the firebaseList have been updated.

With another little hack, i have been able to know when there is no more data :
I just add the following line just before return events; at the end of my forkJoin();

this.stillHaveObjects = (objects.length >= this.nbObjectsToDisplay); 

But is this the right approach ? And how to remove my timeout (cf previous post) ?

I was able to solve this using the Firebase SDK. Care to know how? Or you’re strictly using the AngularFire2?

I am interested in knowing how.

Okay so to accomplish what he did. I did this:

In a provider: (event-data.ts)

getlimitedcategoryList(number): any {
    return firebase.database().ref('/subjectList').limitToLast(number);
  }

In my page: (home.ts)

var a = 15;

export class HomePage {

  constructor(public eventData: EventData,) {
 this.eventData.getlimitedcategoryList(b).on('value', snapshot => {
      rawList10 = [];
      snapshot.forEach(snap => {
        rawList10.unshift({
          id: snap.key,
          subject: snap.val().subject,
          sid: snap.val().sid
        });
      });
      this.subjectsList = rawList10;
    });
    }

This is the class that increments variable “b”

 loadmoresubjects(){
        b+=5
         this.eventData.getlimitedcategoryList(b).on('value', snapshot => {
          let rawList1 = [];
          snapshot.forEach(snap => {
            rawList1.unshift({
              id: snap.key,
              subject: snap.val().subject,
              sid: snap.val().sid
            });
          });
          this.subjectsList = rawList1;
        });

      }

And home.html

 <ion-item-divider>
    Subjects
  </ion-item-divider>
  <div padding>
    <ion-chip *ngFor="let subjects of subjectsList" (click)="presentFilteredAnswers(subjects.subject)">
      <ion-icon name="pin"></ion-icon>
      <ion-label>{{subjects?.subject}}</ion-label>
    </ion-chip>
    <ion-chip (click)="loadmoresubjects()">
      <ion-icon name="pin"></ion-icon>
      <ion-label>More..</ion-label>
    </ion-chip>

  </div>
4 Likes

That’s a good one with unshift. But i have a vey different home.html where i’m using infiniteScrollList.
I will try with your solution, it seems easier to implement and understand.

yes. I’m more flexible with the Firebase SDK. So far I havent had to make any changes to my code I posted previously, works quite well.

Oh and to tell if there are no more objects to load… Hmm… I’ll get back to you with an example on that

@trevaun23 Love this solution.Much cleaner.

@mvrc Did you ever figure out how to get it working with infinite scrolling?

I’ve a workaround

<ion-infinite-scroll [hidden]="!activities.stillHaveEvents" 
    (ionInfinite)="doInfinite($event)"> 
    <ion-infinite-scroll-content loadingSpinner="dots">
    </ion-infinite-scroll-content>
</ion-infinite-scroll>
doInfinite(infiniteScroll) {
		this.activities.finishLoading
			.first()
			.subscribe(() => {
				infiniteScroll.complete();
			});
		this.activities.loadMoreEvents();
	}

and then in my mergeMap() :

public finishLoading: Subject<any>;

[...]

(...values) => {
	events.forEach((event, index) => {event.event = values[index];});
	this.stillHaveEvents = (events.length >= this.cptEventsToDisplay);
	this.finishLoading.next();
	return events;
}
2 Likes

Have you tried using a behaviour subject from rxjs library and emitting a new value on reaching the top of the chat list? Seems to work for me!

Yes. This is exactly what i do but when i’m reaching the bottom of my list (this is not a chat here). This way i can “paginate” the query.

1 Like

Hello mvrc !! I need to create an infinite lazy scroll with Firebase. I found in the forum a post that you also need this solution. Did you do it? Do you mind sharing?
Thank you

Hello @mvdurao.
I’ve just used the functions described above in this topic :slight_smile:

@mvrc Thanks for sharing all this!
Can you define “this.cptEventsToDisplay” and “this.nbObjectsToDisplay”? Where are you setting those totals?