1
votes

I’m doing Angular 2 infinite scrolling for ag-grid and got an issue to synchronize data portion with setRowData. The duplication problem comes after 1st scrolling event handler is called (to get 2nd portion of the data as the 1st was loaded originally, before scrolling) and HTTP request for the page’s data portion is sent. Since only asynchronous HTTP request is now available (synchronous was deprecated), the control is passed to setRowData BEFORE HTTP Response is received. As a result, old row data’s used to populate grid, and 1st & 2nd pages look identical. Any attempts to block execution of setRowData UNTIL HTTP Response arrives, failed. setIntervals() & setTimeout() didn’t block while “while” loop blocked EVERYTHING including HTTP Request/ Response. In latter case, the execution just hangs forever as the condition for the loop exit never met since this flag is updated only after Response is processed. Neither could I make HTTP request synchronous. Bellow’s the code of HTTP function:

private getDataPortionFromServer = function(startRow: number, endRow: number, firstTime: boolean) {
       console.log('getDataPortionFromServer: lastEndRow = ' + this.lastEndRow + ', current endRow' + endRow);
       if (this.lastEndRow == endRow) {
           console.log('getDataPortionFromServer: exiting to avopid dup call');
           return;
       }
       var url: string = ...; //co
  function getDataSynchronously(url, callback) {
      var httpRequest = new XMLHttpRequest();
      httpRequest.open('GET', url, true);
       httpRequest.setRequestHeader('Accept','*/*');
       httpRequest.setRequestHeader('Content-Type','application/json');
       sac.stillRetrieveing = true;
       httpRequest.onreadystatechange = function() {
         if (httpRequest.readyState == 4 && httpRequest.status == 200) {
          if (typeof callback == "function") {
             // apply() sets the meaning of "this" in the callback
             callback.apply(httpRequest);
          }
        }
       }
       httpRequest.send();
  }
  getDataSynchronously(
      url,
      function() {
        console.log('Rrocessing Response : ' + '[' + new Date().toUTCString() + '] ');
        var hs = this.responseText;
         //doing something with data in this.responseText;
                var rd = sac.fitInColumnDefinition(httpResult[0].data); // 'rd' is actual row data for a page
        stillRetrieveing = false; // !!! this is the flag; if false, execution may continue
                                 // otherwise execution should wait until stillRetrieveing = false

        if (firstTime) { //1st portion of Row Data before any scrolling
         setRowData(rd); //1st time no issue, problem comes when scrolling starts
        }
      sac.rowData = rd;
      }
  );
}

//Here's setRowData:

private setRowData(allOfTheData) {
    var sac: SampleAppComponent;
    sac = this;
    var dataSource = {
        rowCount: null, // behave as infinite scroll
        pageSize: sac.pageSize,
        overflowSize: sac.pageSize,
        maxConcurrentRequests: 2,
        maxPagesInCache: 2,

        getRows: (params:any) => {
         console.log('asking for ' + params.startRow + ' to ' + params.endRow);

         sac.getDataPortionFromServer(params.startRow, params.endRow, false); // !!! asynchronous, comes immediately to
                                                                              // next line: allOfTheData = sac.rowData
                                                                              // without waiting for fresh row data

/*
Realy need here some blocking mechanism that would allow:
a) block execution before the next line "allOfTheData = sac.rowData;"
b) during blocking, be able to observe somehow  value of 'stillRetrieveing' flag and detect when it changes
   (something like volatile in JAVA)
c) never exit blocking unless stillRetrieveing == false
*/

         setTimeout( function() {
             allOfTheData = sac.rowData;
                             // take a slice of the total rows
             var dataAfterSortingAndFiltering = sac.sortAndFilter(params.sortModel, params.filterModel,  allOfTheData);

                             // if on or after the last page, work out the last row.
             var lastRow = parseInt(sac.rowsReturned);
                             // call the success callback
             params.successCallback(dataAfterSortingAndFiltering, lastRow);

            }, 500);

        } //getRows: function (params)
    }; //var dataSource

    this.gridOptions.api.setDatasource(dataSource);
}

Would be greatly appreciate any advise or clue.

1

1 Answers

1
votes

Solved it by placing row renderer call back directly into HTTP call back. Had to revamp code quite a bit, but that's the only way i could do it. Promise or Observable didn't work for me.