How to reset/refresh virtualScroll headerFn on data change?


#1

I’m using Ionic virtual scroll w/a custom headerFn, but it doesn’t reset/remove the headers after changing the data.

I want each “header” section to display the date of the report.
This works ok initially, but the virtual headers stick around incorrectly after the array data changes.

If I scroll a bit, some of the headers disappear, but the last one remains even when the data array is completely emptied/replaced. If array.length == 0, the headerFn is not even called, which leaves me no way to remove the errant headers.

Changing the array entirely should force a reset of the virtual scroll, right?
That doesn’t seem to happen, or, at least it doesn’t reset/remove the headers.

How can I completely destroy & recreate the header views?
Can I invoke headerFn directly myself somehow?
Is there some “removeChildren” function I can use?

Failing that, how can I destroy & recreate the entire virtual scroll view?
(Yes, I know that’s an expensive, slow operation … I just need this to work).

Thanks for any help or insight!!

<ion-list [virtualScroll]="reports" [approxItemHeight]="'60px'" [headerFn]="headerForDate"> 
  <ion-item-divider class="listHeader" *virtualHeader="let header">
    	<h2>{{ header }}</h2>
  </ion-item-divider>
  <ion-item class="reportTableCell" *virtualItem="let report" (click)="itemClicked($event, report)">
    <report-table-cell *ngIf="reports.length > 0" [item]=report></report-table-cell>
  </ion-item>
  <ion-item *ngIf="reports.length === 0">
     <h2>No Reports To Show</h2> <!-- This doesn't appear even if reports = []!? -->
  </ion-item>

...........

public reports: any[] = [];
public dividerKey = "";

filterReports(e){ 
  let filter = e.value;
  let res = dataSvc.getReportsFor(filter);
  this.reports = res; //I've tried both directly resetting "this.reports" and using a whole new array. Same issue.
  this.dividerKey = "";
}

//When reports array is reset to [], this is not called, so how can I remove header 0??
headerForDate = (report, index, reports) => {
    
    let reportDate = report.reportDate;
    let lastDivider = this.dividerKey;

    if (reportDate !== lastDivider) {
      this.dividerKey = reportDate;
      return this.dividerKey;
    }
    return null;    
  }

#2

Infinite Scroll seems able/willing to refresh the data array when an item is added to or removed from it, but it does not seem to re-run the headerFn to regenerate the headers/dividers (or presumably the footerFn, which I’m not using but operates on the same principle, so I assume it has the same issue).

I wanted to allow for sorting items by either descending or ascending order, which requires reversing the underlying array. The item cells reversed properly, but the dividers/headers would not update/refresh, and stayed in place over now-incorrect items.

To refresh an inifinite scroll, AND its headers and footers, after changing its data source, I had to:

  1. Import VirtualScroll and ViewChild into the component.
import { ViewChild } from '@angular/core';
import { VirtualScroll } from 'ionic-angular';
  1. Put some #virtualScrollName attribute in the html template to reference in code
<ion-list #virtualScroll [virtualScroll]="myDataSource" [approxItemHeight]="'60px'" [headerFn]="myHeaderFn" virtualTrackBy:trackFn>
  1. Reference the virtualScroll using @ViewChild in the component.
@ViewChild('virtualScroll', { read: VirtualScroll }) virtualScroll: VirtualScroll;
  1. In the function where I want to refresh the headers & footers, call virtualScrollname.readUpdate() and/or virtualScrollname.writeUpdate(), passing the boolean true as an argument to the param “needsClean” … (I tried using only .writeUpdate() but it didn’t work. Using both did. YMMV - try it out).
   this.myDataSource = /* Do something to change the data source for the virtualScroll */
   this.virtualScroll.readUpdate(true);
   this.virtualScroll.writeUpdate(true);