Ionic 2 - Filter search in infinite scroll

2.1k views Asked by At

I am using PouchDB for database and I'm already implement infinite scroll in my project. For the first load, only 40 document will be display and for next scroll, it will load 40 more document. The total document in my database is about 3000 document. I dont have problem in doing infinite scroll, but I have problem in filter data by using infinite scroll. I can search data that already display/viewed but I cannot search data that is not viewed. It's only can filter the data that already loaded. Below is my code.

providers.ts

constructor(public http: Http) {


this.db = new PouchDB('location');
console.log('Hello User Provider',this.db);
this.remote = 'http://data/location';

let options = {
    live: true,
    retry: true
};

this.db.sync(this.remote, options)
  .on('change', function(change){
    console.log('Users provider change!', change);
  })
  .on('paused', function(info){
    console.log('Users provider paused!', info);
  })
  .on('active', function(info){
    console.log('Users provider active!', info);
  })
  .on('error', function(err){
    console.log('users provider error!', err)
  });

}

getUsers(skip,limit){

var total;

return new Promise(resolve => {

  this.db.info().then(function (info) {

    total = info.doc_count;
  })


  this.db.allDocs({
    include_docs: true,
    descending:true,
    limit: limit,
    skip:skip
  })
  .then((result) => {
    this.data = [];

      result.rows.map((row) => {
        if(row.doc._id.substring(0,8) !== '_design/'){
          this.data.push(row.doc);
        }
      })


    resolve(this.data);

    this.db.changes({live: true, since: 'now', include_docs: true})
    .on('change', (change) => {
      this.handleChange(change);
    })

  })
  .catch((error) => {

    console.log('Error when getUsers!', error);

  })

})

}

home.html

<ion-content class="sample-modal-page">
  <ion-searchbar (ionInput)="getItems($event)">
  </ion-searchbar>
  <ion-item *ngFor = "let user of users (click)="dismiss(user.Description)">
    <h3>{{user.Description}}</h3>
    <h4>{{user.code}}</h4>
    <h4>{{user.branch}}</h4>
  </ion-item>

  <ion-infinite-scroll (ionInfinite)="doInfinite($event)">
    <ion-infinite-scroll-content
      loadingSpinner="bubbles"
      loadingText="Loading more data...">
    </ion-infinite-scroll-content>
  </ion-infinite-scroll>

home.ts

users: any = [];
staff: any = [];
searchQuery: string = '';

skip : any = 0;
limit : any = 40;

constructor(public user: User,public loadingCtrl: LoadingController, public viewCtrl: ViewController, public navCtrl: NavController, public navParams: NavParams)
{
  let loadingPopup = this.loadingCtrl.create({
    content: 'Loading data...'
  });

  loadingPopup.present();

  //get data from user provider
  this.user.getUsers(this.skip,this.limit).then(data => {

    this.staff = data;

    this.initializeItems();

    loadingPopup.dismiss();
  });
}

initializeItems() {

  this.users = this.staff;
}

getItems(ev) {

  this.initializeItems();

  var val = ev.target.value;

  if (val && val.trim() != '') {
    this.users = this.users.filter((user) => {

      return (user.Description.toLowerCase().indexOf(val.toLowerCase()) > -1);
    })
  }
}

doInfinite(infiniteScroll){

  setTimeout(() => {

    this.skip = this.skip + this.limit;

    this.user.getUsers(this.skip,this.limit).then((data) => {

      for (var i = 0; i < this.limit; i++) {
        this.users.push(data[i]);
        console.log('Apa ini sebenarnya',this.users);
      }

    });

    console.log('Sync end');
    infiniteScroll.complete();
  },250);
}
2

There are 2 answers

2
Amin MZ On

From your code, you call query by send extra parameter which is skip and limit. Thats mean you will get data only 40 data per query.

  1. If you want to filter at client side (such as data table) you need to get all data and than manipulate it at client side (filter, paging)

  2. If you want to stick with your way (send limit and skip parameter to query function), you must send your filter too, and then reset you limit and skip parameter to 0

0
Apuig On

I had the same issue recently and I will explain the solution from the beginning.

Ionic 2 & 3 have the same procedure.

1. Infinite Scrolling

Render your list using the Ionic docs is so simple: https://ionicframework.com/docs/v3/api/components/infinite-scroll/InfiniteScroll/

2. Searchbar

The same, follow the Ionic docs to configure the searchbar: https://ionicframework.com/docs/v3/api/components/searchbar/Searchbar/

3. Pipe

It is good to use a pipe to filter elements and you will be able to use it in both places, templates and controllers, and reuse it in another components.

For small lists that I do not need the infinite scroll I put it directly in a template:

<ion-list>                                                                                                                                                                     
  <button *ngFor="let item of items | search : searchbarValue:searchbarFilters">

For long cases in a controller:

let filteredOptions = new SearchPipe().transform(this.items, this.searchbarValue, this.searchbarFilters);

My Real Case

In my situation, this.items contains 2.000 values and for that reason I can not render them, so I render only the filtered elements using the infinite scroll.

I paste my own code to show you how it looks all together.

template.html

<ion-searchbar                                                                                                                                                               
  [placeholder]="searchbarPlaceholder"                                                                                                                                       
  (ionInput)="onSearch($event)"                                                                                                                                              
  [(ngModel)]="searchbarValue">                                                                                                                                              
</ion-searchbar>

<!-- List filtered elements -->
<ion-list>                                                                                                                                                                     
  <button *ngFor="let item of filteredItems">

controller.ts

dynamicOffset: number = 0;
dynamicLimit: number = 30;
offset: number = 0;
limit: number = 30;

/**
 * This function is called when some new value is placed in the searchbar.
 * I have two arrays:
 * - Original list with 2.000 values (this.items)
 * - Filtered list empty (this.filteredItems)
 */
onSearch(): void {
  // on every search I reset my filtered list                                                                                                                                                       
  this.filteredItems.length = 0;
  // I call the pipe passing by parameter the ORIGINAL list of items,
  // the searchbarValue and the properties to look them for.
  // I receive the filtered items.
  let filteredItems = new SearchPipe().transform(this.items, this.searchbarValue, this.searchbarFilters);                                                                  
  // I reset the limits of the infinite scroll because I will be filtering in a new list
  this.dynamicOffset = this.offset;                                                                                                                                            
  this.dynamicLimit = this.limit;                                                                                                                                                                                                                                                                                                                             

  this.loadItems(filteredItems);                                                                                                                                           } 

/**                                                                                                                                                                            
* Load items.                                                                                                                                                                 
*/                                                                                                                                                                            
loadItems(items: any = []): void {                                                                                                                                           
  let item;                                                                                                                                                                    
  while (this.dynamicOffset < this.dynamicLimit) {                                                                                                                             
    item = items[this.dynamicOffset];                                                                                                                                        
    if (!item) break;                                                                                                                                                          
    this.filteredItems.push(item);                                                                                                                                           
    this.dynamicOffset++;                                                                                                                                                      
  }

  this.dynamicLimit = this.dynamicLimit + this.limit;                                                                                                                          
}

Anyway, this is an idea how you can resolve this issue. There are more options but, in my case, this code resolved my worries.