2

I'm working on a requirement where I have a datasource named 'emailSearchResults' where I search for email messages metadata and load the results in the datasource.

The fields in the datasource are not relevant, however I set the datasource to have 50 records per page as per the below screenshot: enter image description here

The script I used to load the datasource is shown in the query field, that call the following script:

function getMessageDetails(userId, msgID)
{
  var messageDetails = [];
  var messageData;
  var msgID_,subject_,from_,date_;

  messageData=Gmail.Users.Messages.get(userId,msgID,{format:"metadata", metadataHeaders:["Message-ID", "Subject", "From", "Date"]});

  console.log(messageData.payload.headers);

  //console.log(msgID);
  //console.log(messageData.payload.headers[3].value);

  date_="<na>";
  from_="<na>";
  subject_="<na>";
  msgID_="<na>";

  for (var counter =0;counter<4;counter++)
  {
    if (messageData.payload.headers[counter].name=="Message-ID")
    {
      msgID_=messageData.payload.headers[counter].value;
    }

    if (messageData.payload.headers[counter].name=="Subject")
    {
      subject_=messageData.payload.headers[counter].value;
    }

    if (messageData.payload.headers[counter].name=="From")
    {
      from_=messageData.payload.headers[counter].value;
    }

    if (messageData.payload.headers[counter].name=="Date")
    {
      date_=messageData.payload.headers[counter].value;
    }
  }

  messageDetails.push(date_);
  messageDetails.push(from_);
  messageDetails.push(subject_);
  messageDetails.push(msgID_);

  return messageDetails;
}


function searchMessages(userId,condition)
{
  //
  // first we build the conditions
  // we can make it fixed
  // or we can make it dynamic
  var searchResult;
  var deleteResult;
  var currentMessage;
  var results = [];
  var pageToken;
  var params = {};
  var _stat;
  var options = {
    includeSpamTrash: "true",
    pageToken: pageToken
  };
  var msgRecord = [];

  do
  {
    searchResult=Gmail.Users.Messages.list(userId,options);

    for (var i = 0; i < searchResult.messages.length; i++)
    {
      var record=app.models.emailSearchResults.newRecord();
      msgRecord=getMessageDetails(userId,searchResult.messages[i].id);

      record.msgMainID=searchResult.messages[i].id;
      record.msgID=msgRecord[3];
      record.subject=msgRecord[2];
      record.senderAddress=msgRecord[1];
      record.msgDate=msgRecord[0];

      /*console.log(searchResult.messages[i].id);
      console.log(msgRecord[3]);
      console.log(msgRecord[2]);
      console.log(msgRecord[1]);
      console.log(msgRecord[0]);

      return;*/
      results.push(record);
      msgRecord=null;
    }

    if (searchResult.nextPageToken) {
      options.pageToken = searchResult.nextPageToken;
    }
  } while (searchResult.pageToken);

  searchResult=null;

  return results;
}

On the main page I put a table and linked it to the datasource, and I enabled pagination on the table, so I get the pager buttons at the bottom of the table as below: enter image description here enter image description here

When I execute the app and the datasource is filled, I see the first page results in a correct way, however when I want to move to the next page, I click the next page button and once the loading is complete I find out that I still see the same results from the first page on the table.

I am not familiar with how to make the table show the results of the second page then the third page, and I am going in circles on this...

Hope the explanation is clear and addresses the issue..

I would really appreciate any help on this! Regards

Bluescrod
  • 81
  • 1
  • 7
  • 1
    There was an issue with pagination on a calculated datasource, which I am guessing your datasource is. It would appear that this may still not have been fixed. You may want to see if there is a bug filed for this issue and star it or if a bug report has not been filed then go ahead and file one. – Markus Malessa Nov 13 '18 at 18:57
  • Hi @MarkusMalessa, yes it is a calculated data source, I'll check the bug reports about this.. But according to App Maker Team's reply below maybe this is the normal behavior? The modifications that they proposed below did actually work perfectly for the datasource that I created.. – Bluescrod Nov 13 '18 at 22:59
  • Upon further inspection, I agree with @MarkusMalessa, it seems that this is likely a bug. – The Support Group Nov 15 '18 at 14:54

1 Answers1

2

Currently pagination isn't working as expected with calculated datasources. You can, however, build your own. There are several changes you'll need to make to accomplish this. First you'll want to refactor your searchMessages function to something like this:

function searchMessages(userId, pageToken){

  var results = [];
  var options = {
    includeSpamTrash: "true",
    pageToken: pageToken,
    maxResults: 50
  };

    var searchResult = Gmail.Users.Messages.list(userId, options);

    for (var i = 0; i < searchResult.messages.length; i++){
      var record = app.models.emailSearchResults.newRecord();
      var msgRecord = getMessageDetails(userId,searchResult.messages[i].id);

      record.msgMainID = searchResult.messages[i].id;
      record.msgID = msgRecord[3];
      record.subject = msgRecord[2];
      record.senderAddress = msgRecord[1];
      record.msgDate = msgRecord[0];

      results.push(record);
    }

  return {records: results, nextPageToken: searchResult.nextPageToken};
}

Then you'll want to change your datasource query. You'll need to add a number parameter called page.

var cache = CacheService.getUserCache();
var page = query.parameters.page || 1;
var pageToken;
if(page > 1){
  pageToken = cache.get('pageToken' + page.toString());
}

var results = searchMessages('me', pageToken);

var nextPage = (page + 1).toString();
cache.put('pageToken' + nextPage, results.nextPageToken);

return results.records;

You'll need to modify the pagination widget's various attributes. Here are the previous/next click functions:

Previous:

widget.datasource.query.pageIndex--;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();

Next:

widget.datasource.query.pageIndex++;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();

You should be able to take it from there.

  • This is great, really appreciate the help. It worked as explained... I had to tweak some stuff in the pagination widget but it did work exactly as I was expecting. – Bluescrod Nov 13 '18 at 22:57
  • It worked, like @Bluescrod said in the comments, I had to tweak the visibility of the prev/next buttons as well as the definition to disable them. – jorgeAChacon Nov 16 '18 at 17:54
  • @Bluescrod how did you end up disabling the "Next page" button on the Client side? – jorgeAChacon Nov 16 '18 at 19:20
  • @jorgeAChacon if I understood the flow correctly, the datasource is being loaded with the next page of the query each time I click the next/prev button. I still haven't worked on that yet really, since I want to get to a fully working model for what I want to do then I'll work on the proper visibility settings for next/prev buttons. However, I believe I can make a custom condition to look at the pageToken/page number or make a custom counter to control the visibility of those 2 buttons... Just rough thoughts still really, I'll need to get working on that really soon! – Bluescrod Nov 17 '18 at 18:27
  • @jorgeAChacon to get myself going for the time being, I changed the visibility settings for the next/prev buttons form the binding to an explicit value and I set it to enabled for both buttons. I also changed the visibility setting for the whole pager widget to explicit visible as well for now. When I reach the max page count, I am still able to click next/prev, and the page numbers will be updated by a wrong value. I'll have to address this as explained in the previous comment though. – Bluescrod Nov 17 '18 at 18:30