0

I am creating a Google Apps Script which takes the data from Google Sheets and renders it to jquery datatable.

CASE 1: (ifUsingSheetAsDB = TRUE) I am able to fetch and render the data successfully by filtering required data to a short Google sheet's table (short table) in a separate sheet from a large table (big table) using Google sheet's Filter formula and then reading that filtered table in my .gs file. This case in the code is wrapped with "ifUsingSheetAsDB"

My final data coming from .gs file to datatable is (in this case)

function userClickedCheck(name, code) {
  
  var ret = validator(name, code);  //name-code checker
  var range = wsTest.getRange("A2:A").getValues();  //short table is generated in the sheet Test here
  
  if(gInDebug || gAppDebug)
  {
    Logger.log("ret" + ret);  //checking validation
  }
  
  if(ret == 1)  //success
  {
    if(ifUsingSheetAsDB)  //reading "short table" from G Sheet
    {
      var rangelen = range.length;
  
      //Logger.log(range.getDisplayValues());
    
      var lastRow = getLastRowSpecial(range);  //custom function which finds the last filled row

      range = wsTest.getRange("A2:L" + (lastRow + 1));  //last filled row is the table length
      range = range.getDisplayValues();  //GSheet API returns string[][]
    }   
    else
    {
      //TODO without sheet as DB////////////////////////

      range = garySelectedRange;  //declared as let garySelectedRange = [];
      //TODO without sheet as DB end ////////////////////////
    }
  }
  else
  {
    range = [[]];
  }

  
  if(gAppDebug || gInDebug)
  {
    Logger.log("length of range " + range.length);  //Apps Script Point 1
    Logger.log(range);  //Apps Script Point 2
  }
  return range;
}

The range is captured in the datatable js as below:

function checkFinished(rangeValues)
{
  if ( ! table.data().any() ) 
  {
    //alert( 'Empty table' );
  }
  else
  {
    table
    .clear()
    .draw();
  }

  //var len2D = rangeValues.length;

  //alert("Reached inside SubmitFinished " + len2D);
  //TODO debug
  console.log("printing rangeValues " + rangeValues.length)  //console debug
  console.table(rangeValues);  //console debug
  //TODO debug end

  table.rows.add( rangeValues )
    .draw();
}

This is working real good. No issues here. I have read about range.getDisplayValues(); which returns string[][] according to https://developers.google.com/apps-script/reference/spreadsheet/range

Case 2: (ifUsingSheetAsDB = FALSE) Now I want to replace the data fetch and instead of using G Sheet's integrated Filter functions in the sheet, I am processing the whole "big table" by fetching data to .gs file and using my custom Filter:

function filterAndCreate(name)
{
  var inneri = 0;
  var innerj = 0;
  for (var i in garyRangePO)  
  {
    if(garyRangePO[i][1] == name)
    {
      garySelectedRange.push(
        [
        garyRangePO[i][0] + "/2122",
        garyRangePO[i][5],
        garyRangePO[i][6],
        garyRangePO[i][7],
        garyRangePO[i][8],
        garyRangePO[i][9],
        garyRangePO[i][10],
        garyRangePO[i][11],
        garyRangePO[i][12],
        garyRangePO[i][14],
        garyRangePO[i][13],
        garyRangePO[i][20]
        ]
        );
    }
  }

  if(gInDebug || gAppDebug)
  {
    Logger.log(garySelectedRange);   
  }
}

.js side it's the same function.

where garyRangePO is "big table" and garySelectedRange is "short table" and declared as let garyRangePO = []; let garySelectedRange = []; in global scope.

If I debug this in Apps Script, my debug points when success gives me something like this: CASE 1: enter image description here

CASE 2: enter image description here

Everything looks great till now from return value perspective too. For both the cases Apps Script debugger is showing type as enter image description here

However, when I actually run my code... Case 1 console log (where data is properly populated to datatable and works like a charm): enter image description here

Case 2 console log: enter image description here

Now here I need help please. I am new to js and webapp and all. So please pardon me in advance. Thank you.

  • Can you provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example), clearly showing the expected outcome and the actual outcome you are getting? – Iamblichus Sep 23 '21 at 08:54
  • @lambichus Thanks for your comment. I think I just found the solution that GAS doesn't have something like a global scoped variable.https://stackoverflow.com/questions/24721226/how-to-define-global-variable-in-google-apps-script – Preet Mehta Sep 23 '21 at 10:48
  • Could you post a solution explaining the relationship between this and your question? I'm not sure I understand this, based on the information you provided in your question. – Iamblichus Sep 24 '21 at 07:10
  • Sure. Adding an answer, for any future references. – Preet Mehta Sep 28 '21 at 07:51

1 Answers1

0

First of all, pardon me if my concepts are wrong, but I am yet a starter with all of these.

So basically, it looks like GAS is re-initiating globally scoped vars on the server-side every time before a function in the .gs (server-side code) is executed. Now to solve this issue, one can follow How to define global variable in Google Apps Script

It works but doesn't solve my query, as this [key, value] is same for every connection created to the app. Meaning, if two users are using this app simultaneously, irrespective of the function they are executing at T=t, this value will be same for both. I am not sure how to use this answer if someone is looking for a parallel multi-user app which shares a common DB written in the Sheets. (Maybe check for bind and release and add keys as an array representing each connection?)

Also, My code is using big sum of global data, and I feared saving that whole matrix in 'myvalue' and creating array for 'mykeys' for each connection,

PropertiesService.getScriptProperties().setProperty('mykey', 'myvalue'); 

var myvalue = PropertiesService.getScriptProperties().getProperty('mykey');

However, I had re-initiated required data every time when a function is executed for a connection according to the input from client-side js. I think this is not a solution, but this works and takes a bit more time while executing.

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • `I am not sure how to use this answer if someone is looking for a parallel multi-user app` If you want each user to retrieve a different value, you can use [userProperties](https://developers.google.com/apps-script/reference/properties/properties-service#getuserproperties) instead of script properties. Not sure if that's what you want, though. If you think that's the direction you want, I'd consider posting an answer with more information. – Iamblichus Sep 28 '21 at 10:40
  • That would be worth looking into. Can you please post it? I am looking for each user to retrieve a different value, but you don't know the number of max users prior. I am using G sheets as the database, this G sheet has a table which has user specific infos... once any user "logs in" he/she can retrieve respective info. – Preet Mehta Sep 29 '21 at 08:25
  • Can you clarify how the value corresponding to each user is defined? Where does that information come from? – Iamblichus Sep 29 '21 at 08:58
  • G sheet has a big table which is used as the data to be shown. This table has data of every user and this is unfiltered and new data is added into it every day. Now whoever wants to see his/her data comes through the App, logs in (validates themselves) and accordingly this big table is filtered to show user respective data. Earlier approach was to use another sheet to hold this filtered data and show it to user, but that doesn't allow simultaneous access. So now I filter this big table in .gs and this filtered table is what I want to keep as a value globally. – Preet Mehta Sep 29 '21 at 14:40
  • Because user will be performing various actions on this data, I want respective user's filtered table to float in the .gs between the functions. This is supposed to be done for N number of connections. – Preet Mehta Sep 29 '21 at 14:43
  • Does the table of data has the user email to identify which data corresponds to each user? If that's the case, this could be as easy as retrieving the current user email via [Session.getEffectiveUser().getEmail()](https://developers.google.com/apps-script/reference/base/session#getEffectiveUser()), look for that email in the table and retrieve the corresponding row. Would that be useful to you? – Iamblichus Sep 29 '21 at 15:43
  • Table doesn't have email but has the name, and in App I have a name and user code to identify the user. Also I am not sure if Session.getEffectiveUser().getEmail() would work as this app is supposed to be worked even without Google Account login. My main concern is to keep the respective user's filtered tables in permanent memory of server and how to do it? – Preet Mehta Sep 30 '21 at 06:18
  • `this app is supposed to be worked even without Google Account login` In that case `UserProperties` would not be useful. But why not storing a different ScriptProperty for each user, with the user name identifying the property key? – Iamblichus Sep 30 '21 at 11:06
  • That's a possibility, I will check and revert on that. I just have to check if scriptproperty can store 2d matrix table or not. – Preet Mehta Sep 30 '21 at 17:27
  • It can only store strings, but you can just [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) your 2D array when storing the property and [JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) it when retrieving it. – Iamblichus Oct 01 '21 at 07:10