Quantcast
Channel: Ionic Framework - Ionic Forum
Viewing all articles
Browse latest Browse all 49258

Firebase pagination with infinite scroll and CRUD

$
0
0

Hi,

I’m implementing ionic firebase ( firestore ) pagination feature with infinite scroll and crud.

When I scroll down, it looks working. At the end of data it disable infinite scroll as well.

After that I implemented update/delete features which shows a bug.

The problem is, when I do update/delete action it trigger observable subscribe method which added up the result ( not merge and create another Observable)

My question is ( not sure if this is valid point though )

  1. How to prevent adding up new result to existing result, when I update/delete action.

  2. How to merge multiple observable to one single observable ( concat )

  3. In this use case, Is Subscription better than Observable?

Any suggestion would be greatly appreciated.

Thanks.

Here is a source code.

    // Test.ts
    interface Test {
    doc?: any;
    id: number;
    title: string;
    }
//home.page.html
    <ion-header>
      <ion-toolbar color="primary">
        <ion-title>Total {{testList?.length}}</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-list>
        <ion-item *ngFor="let test of testList">
          <ion-label class="ion-text-wrap">
            <p>{{test.id}}</p>
            <p>{{test.title}}</p>
          </ion-label>
          <ion-button color="secondary" (click)="deleteTestDataById(test.doc.id)">
            <ion-icon slot="icon-only" name="trash"></ion-icon>
          </ion-button>
        </ion-item>
      </ion-list>
    
      <ion-fab vertical="bottom" horizontal="end" slot="fixed">
        <ion-fab-button>
          <ion-icon name="add"></ion-icon>
        </ion-fab-button>
        <ion-fab-list side="top">
          <ion-fab-button color="light"  (click)="deleteAllTestData()">
            <ion-icon name="close"></ion-icon>
          </ion-fab-button>
          <ion-fab-button color="light"  (click)="addAllTestData()">
            <ion-icon name="add"></ion-icon>
          </ion-fab-button>
        </ion-fab-list>
      </ion-fab>
    
      <ion-infinite-scroll (ionInfinite)="getMoreData($event)">
        <ion-infinite-scroll-content loading-spinner="circles" loading-text="Loading...">
        </ion-infinite-scroll-content>
      </ion-infinite-scroll>
    
    </ion-content>
//home.page.ts
    import {Component, OnInit, ViewChild} from '@angular/core';
    import {Subscription} from 'rxjs';
    import {IonInfiniteScroll} from '@ionic/angular';
    import {DataService} from '../services/data.service';
    
    @Component({
      selector: 'app-home',
      templateUrl: 'home.page.html',
      styleUrls: ['home.page.scss'],
    })
    export class HomePage implements OnInit {
    
      // result, I also tested with Observable<any> but same.
      testList: Test[] = [];

      testSubscription: Subscription;

	// 15 records per page
      recordsPerPage = 15;

	// firestore next cursor
      startAfterCursor: any;

	// End of data check
      endOfData = false;
    
      @ViewChild(IonInfiniteScroll) infinite: IonInfiniteScroll;
    
      constructor(private dataService: DataService) {
      }
    
      ngOnInit(): void {
        this.getMoreData(null);
      }
    
      getMoreData(event: any) {
        this.testSubscription = this.dataService.getPaginatedData(this.recordsPerPage, this.startAfterCursor)
          .subscribe(result => {
    
	// concat returned data to existing result
            this.testList = this.testList.concat(result.slice(0, this.recordsPerPage));
    
            if (this.recordsPerPage > result.length) {
              this.endOfData = true;
              this.infinite.disabled = true;
            } else {
              this.endOfData = false;
              this.infinite.disabled = false;
            }
    
	// for next call, save last firestore doc info from the result
            if (result[this.recordsPerPage - 1] !== undefined) {
              this.startAfterCursor = result[this.recordsPerPage - 1].doc;
            }
          });
    
        if (event) {
          event.target.complete();
        }
      }
    
      deleteTestDataById(id: any) {
        this.dataService.deleteTestDataById(id);
      }
    
      deleteAllTestData() {
        this.dataService.deleteAllTestData();
      }
    
      addAllTestData() {
        this.dataService.addAllTestData();
      }
    }
 //data.service.ts
    import {Injectable} from '@angular/core';
    import {AngularFirestore, QueryFn} from '@angular/fire/firestore';
    import {Observable} from 'rxjs';
    import {map} from 'rxjs/operators';
    import {TestData} from '../model/TestData';
    
    @Injectable({
      providedIn: 'root'
    })
    export class DataService {
    
      FIREBASE_TEST_NODE = 'FB_TEST_NODE';
    
      constructor(private angularFireStore: AngularFirestore) {
      }
    
      getPaginatedData(recordsPerPage, cursor?): Observable<any> {

        let queryFn: QueryFn;
        if (cursor === undefined) {
          queryFn = value => value.orderBy('id').limit(recordsPerPage);
        } else {
          queryFn = value => value.orderBy('id').limit(recordsPerPage).startAfter(cursor);    
        }

        return this.angularFireStore
          .collection(this.FIREBASE_TEST_NODE, queryFn)
          .snapshotChanges()
          .pipe(
	  // typical data mapping
            map(result => {
              return result.map(allData => {
                const data = allData.payload.doc.data();
                const doc = allData.payload.doc;
                return {doc, ...(data as object)};
              });
            })
          );
      }
    
      deleteTestDataById(id: any) {
        return this.angularFireStore.doc(this.FIREBASE_TEST_NODE + '/' + id).delete();
      }
    
      addAllTestData(): any {
        TestData.PaginationTestData
          .forEach(data => {
              this.angularFireStore.collection(this.FIREBASE_TEST_NODE)
                .add(data);
            }
          );
      }
    
      deleteAllTestData(): any {
        const listTestDBRef = this.angularFireStore.collection(this.FIREBASE_TEST_NODE)
          .get()
          .subscribe(result => {
            result.forEach(element => {
              element.ref.delete();
            });
          });
      }
    }
//TestData.ts
    export const TestData = {
      PaginationTestData: [
        {
          id: 1,
          title: 'Test1 Title',
        },
        {
          id: 2,
          title: 'Test2 Title',
        },
        {
          id: 3,
          title: 'Test3 Title',
        },
        {
          id: 4,
          title: 'Test4 Title',
        },
        {
          id: 5,
          title: 'Test5 Title',
        },
        {
          id: 6,
          title: 'Test6 Title',
        },
        {
          id: 7,
          title: 'Test7 Title',
        },
        {
          id: 8,
          title: 'Test8 Title',
        },
        {
          id: 9,
          title: 'Test9 Title',
        },
        {
          id: 10,
          title: 'Test10 Title',
        },
        // 40 more records for test.
      ]
    };

1 post - 1 participant

Read full topic


Viewing all articles
Browse latest Browse all 49258

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>