0

In my current job with spreadsheet, all inserted data passes through a test, checking if the same value is found on the same index in other sheets. Failing, a caution message is put in the current cell.

//mimimalist algorithm
function safeInsertion(data, row_, col_)
{
  let rrow = row_ - 1; //range row
  let rcol = col_ - 1; // range col
  const active_sheet_name = getActiveSheetName(); // do as the its name suggest
  const all_sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  
  //test to evaluate the value to be inserted in the sheet    
  for (let sh of all_sheets)
  {
    if (sh.getName() === active_sheet_name)
      continue;  
    //getSheetValues do as its name suggest.
    if( getSheetValues(sh)[rrow][rcol] === data )
      return "prohibited insertion"
  }
  return data;  
} 
// usage (in cell): =safeInsertion("A scarce data", ROW(), COLUMN())

The problems are:

  • cached values confuse me sometimes. The script or data is changed but not perceived by the sheet itself until renewing manually the cell's content or refreshing all table. Is there any relevant configuration available to this issue?
  • Sometimes, at loading, a messing result appears. Almost all data are prohibited, for example (originally, all was fine!).

What can I do to obtain a stable sheet using this approach?

PS: The original function does more testing on each data insertion. Those tests consist on counting the frequency in the actual sheet and in all sheets.

EDIT:

In fact, I can't create a stable sheet. For test, a let you a copy of my code with minimal adaptations.

function safelyPut(data, max_onesheet, max_allsheet, row, col)
{
  // general initialization
  const data_regex = "\^\s*"+data+"\s*$"
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const activesheet = spreadsheet.getActiveSheet();
  const active_text_finder = activesheet.createTextFinder(data_regex)
                                        .useRegularExpression(true)
                                        .matchEntireCell(true);
  const all_text_finder = spreadsheet.createTextFinder(data_regex)
                                     .useRegularExpression(true)
                                     .matchEntireCell(true);
  const all_occurrences = all_text_finder.findAll();

  //test general data's environment
  const active_freq = active_text_finder.findAll().length;
  if (max_onesheet <= active_freq)
    return "Too much in a sheet";
  const all_freq = all_occurrences.length;
  if (max_allsheet <= all_freq)
    return "Too much in the work";
  
  //test unicity in a position
  const active_sname = activesheet.getName();
  for (occurrence of all_occurrences)
  {
    const sname =  occurrence.getSheet().getName();

    //if (SYSTEM_SHEETS.includes(sname))
      //continue;

    if (sname != active_sname)
    if (occurrence.getRow() == row && occurrence.getColumn() == col)
    if (occurrence.getValue() == data)
    {
      return `${sname} contains same data with the same indexes.`;
    };
  }

  return data;  
}

Create two or three cells and put randomly in a short range short range a value following the usage

=safeInsertion("Scarce Data", 3; 5; ROW(), COLUMN())

Do it, probably you will get a unstable sheet.

Daniel Bandeira
  • 360
  • 1
  • 2
  • 12
  • 1
    I have to apologize for my poor English skill. Unfortunately, I cannot understand `cached values do not reevaluate the function.` and `Sometimes, at loading, a messing result appears. Almost all data are prohibited, for example (originally, all was fine!).`. Can I ask you about the detail of it? – Tanaike Feb 06 '22 at 12:20
  • Sorry for my english and preconceptions. I've meant that some cells values are cached. So, when a update occurs in the script or in the sheet, the values should be updated (and,some times, changed). Because of this, I need to delete the value of the cell or and reinsert the deleted formula to get the correct value. I hope I made it clearer this time. – Daniel Bandeira Feb 06 '22 at 12:30
  • 1
    Thank you for replying. If you want to refresh your custom function, this thread is useful. https://stackoverflow.com/q/61300428/7108653 – Tanaike Feb 06 '22 at 12:34
  • Although I'm not sure whether I could correctly understand your question and this is the direct solution to your issue, I proposed an answer. Could you please confirm it? If I misunderstood your question and that was not useful, I apologize. – Tanaike Feb 06 '22 at 13:19
  • 1
    You can force your sheet to update all pending changes made via Apps Script with [`SpreadsheetApp.flush()`](https://stackoverflow.com/questions/41175326/why-do-we-use-spreadsheetapp-flush) ([docs](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush)) - is this the kind of thing you're looking for? – Rafa Guillermo Feb 07 '22 at 08:39

1 Answers1

2

About cached values confuse me sometimes. The script is changed but not perceived by the sheet until renewing manually the cell's content or refreshing all table. No relevant configuration available to this issue?, when you want to refresh your custom function of safeInsertion, I thought that this thread might be useful.

About Sometimes, at loading, a messing result appears. Almost all data are prohibited, for example (originally, all was fine!). and What can I do to obtain a stable sheet using this approach?, in this case, for example, how about reducing the process cost of your script? I thought that by reducing the process cost of the script, your situation might be a bit stable.

When your script is modified by reducing the process cost, how about the following modification?

Modified script:

function safeInsertion(data, row_, col_) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const range = ss.createTextFinder(data).matchEntireCell(true).findNext();
  return range && range.getRow() == row_ && range.getColumn() == col_ && range.getSheet().getSheetName() != ss.getActiveSheet().getSheetName() ? "prohibited insertion" : data;
}
  • The usage of this is the same with your current script like =safeInsertion("A scarce data", ROW(), COLUMN()).

  • In this modification, TextFinder is used. Because I thought that when the value is searched from all sheets in a Google Spreadsheet, TextFinder is suitable for reducing the process cost.

References:

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • This reduction of the process seems to me really valuable! I haven't yet understood how this change could bring stabilization to the output, but, definitely is smarter and quicker than the original code. Thank you. – Daniel Bandeira Feb 06 '22 at 13:46
  • @Daniel Bandeira Thank you for replying. If this was not the direct solution to your issue, I apologize. At that time, can you provide the sample Spreadsheet for replicating the issue? By this, I would like to try to understand your situation and try to think of a workaround. – Tanaike Feb 07 '22 at 05:15
  • I have done a edition, Initially all starts fine. Suddenly, unexpected results again. If you interest, it's easy now to reproduce my situation. Thank you too much for all support you've gave us! – Daniel Bandeira Feb 07 '22 at 11:12
  • 1
    @Daniel Bandeira Thank you for replying. I saw your updated question. I think that your additional script is 2nd question. Unfortunately, I cannot understand what you want to do using your added script. This is due to my poor skill. I deeply apologize for this. But I would like to support you. When I could correctly understand your 2nd question, I would like to think of the solution. But now I deeply apologize that I cannot resolve your 2nd question soon. This is due to my poor skill. I deeply apologize for this again. I would be grateful if you can forgive my poor English skill. – Tanaike Feb 07 '22 at 11:54