0

I have been looking into other questions posted but haven't been able to understand how to apply the solutions to my situation. Hopefully an answer here will make it a lot more obvious to others also.

I have a function in Code.gs which copies rows of data (which meet a certain criteria) into another spreadsheet.

function CopyRowsToAUDistDataSheet() {
  var source = SpreadsheetApp.getActiveSpreadsheet();
  var target = SpreadsheetApp.openById("######");
  var lastRow = source.getLastRow();
  var source_sheet = source.getSheetByName("Raw Data");
  var target_sheet = target.getSheetByName("Distributors");

  var source_range = source_sheet.getDataRange();
  var target_range = target_sheet.getDataRange();

  var i = 2;
  while (i <= lastRow) {
  if (source_sheet.getRange("C"+i).getValue() == "Distributor" ) {
    var A = source_sheet.getRange("A"+i).getValue();
    var B = source_sheet.getRange("B"+i).getValue();
    var C = source_sheet.getRange("C"+i).getValue();
    var D = source_sheet.getRange("D"+i).getValue();
    var E = source_sheet.getRange("E"+i).getValue();
    var F = source_sheet.getRange("F"+i).getValue();
    var G = source_sheet.getRange("G"+i).getValue();
    var H = source_sheet.getRange("H"+i).getValue();
    var I = source_sheet.getRange("I"+i).getValue();
    var J = source_sheet.getRange("J"+i).getValue();
    var K = source_sheet.getRange("K"+i).getValue();
    var L = source_sheet.getRange("L"+i).getValue();
    var M = source_sheet.getRange("M"+i).getValue();
    var N = source_sheet.getRange("N"+i).getValue();
    N *= 100;
    var data = [A,B,C,D,E,F,G,H,I,J,K,L,M,N];
    target_sheet.appendRow(data);
    i++;
  } else {
    i++;
  }
}
}

Each time the data is copied across, updated values in the cells, OR updates made to the data from within the above function are not recognised (Note the addition of the "N *= 100" to multiply the value by 100 to fix an issue with percentages).

I am having trouble figuring out how to bypass this caching issue with the above function. I have tried passing it timestamps etc but no luck. I am sure I am missing something obvious here.

Any help will be greatly appreciated.

I have tried working with the solutions/answers posted here:

Refresh data retrieved by a custom function in google spreadsheet

Script to summarise data not updating

UPDATE:

The function is now updated to the following:

function CopyRowsTest() {
  var source = SpreadsheetApp.getActiveSpreadsheet();
  var target = SpreadsheetApp.openById("###");
  var source_sheet = source.getSheetByName("Raw Data");
  var target_sheet = target.getSheetByName("Distributors");
  var source_range = source_sheet.getDataRange();
  var source_data = source_range.getValues();

  for (var i = 1, r = source_data.length; i < r; i++) {
    if (source_data[i][2] === 'Distributor') {
      // Multiply % data by 100 to work around bug
      source_data[i][13] *= 100;
      source_data[i][16] *= 100;
      source_data[i][23] *= 100;
      source_data[i][29] *= 100;
      source_data[i][31] *= 100;

      target_sheet.appendRow(source_data[i]);
    }
  }
}
Community
  • 1
  • 1
user3213842
  • 3
  • 1
  • 3
  • By "caching issue" - I assume you mean the custom function recalculation issue: https://code.google.com/p/google-apps-script-issues/issues/detail?id=1131 – eddyparkinson Jan 20 '14 at 07:03
  • Have you tried forcing the target sheet to flush? Also, please consider your aggressive use of `getRange`. Try something like: `var source_data = source_range.getValues(); for( var i = 1, r = source_data.length; i < r; i++) { if (source_data[i][2] === 'Distributer') { target_sheet.appendRow(source_data[i]); } }` Sorry for any syntax errors, commenting on a phone is tough. – fooby Jan 20 '14 at 12:48
  • @eddyparkinson - I am not entirely sure what you linked to is the same issue I am experiencing. Whenever the data in the source spreadsheet, or the function changes, the data that is pulled through remains the same - almost like it is cached. For example, I had some cells which contained numbers which I needed to multiply by 100 in order for them to display correctly. Added the functionality into the function and the data still came through the same. – user3213842 Jan 20 '14 at 23:58
  • @fooby - Thank you very much for pointing that out. I am still very green with all this! If it helps, I have updated original question to show the updated function. – user3213842 Jan 20 '14 at 23:59
  • @fooby - In regards to forcing the target sheet to flush. I have read the below link and it sounds like this wont resolve my problem? Happy to hear if you think otherwise of course. http://stackoverflow.com/questions/18835689/spreadsheetapp-flush-doesnt-cause-a-recalc-if-there-is-no-visible-change-to-t – user3213842 Jan 21 '14 at 00:16
  • Try writing a value to the sheet, this seams to cause the whole sheet to recalculate, so should get round the problem. – eddyparkinson Jan 21 '14 at 00:47
  • @eddyparkinson - Do you mean the source sheet or target sheet? So I could write any value to any cell in the sheet (current date and time for example) and this should force the sheet to recalculate? – user3213842 Jan 21 '14 at 02:24
  • @user3213842 yes, just change the value of a cell in your source sheet. It you notice, random formula values change every time any cell is changed. – eddyparkinson Jan 21 '14 at 05:10
  • As a gut check, are you running this function on a timer? Do you expect it to update information on edit? Are you aware that this function will only ever append the information to the target spreadsheet? It will never replace/update rows. If you are using old Google Spreadsheets, the you can accomplish this cross-sheet filter using `IMPORTRANGE` inside a `FILTER` function. Finally, the multiplication *is not nessesary*. Check that the format of the destination cells is set to percent. I'll post an example based on your code shortly. – fooby Jan 21 '14 at 17:49
  • You can find what I believe to be a mock up of your situation in the follow sheets and code: [Source Sheet](http://goo.gl/cy0hNY) | [Destination Sheet](http://goo.gl/izossl) | [Code](http://goo.gl/I83pBE) – fooby Jan 21 '14 at 18:02
  • @eddyparkinson - Thank you, I have tried adding the current date and time to a cell at the end of each row in the source sheet. This means this data will be copied across to the target sheet also. This doesn't seem to fix the problem. – user3213842 Jan 21 '14 at 23:20
  • @fooby - Thank you, I have the custom function setup as a menu option so I can run it manually. Also I am aware the way it is setup means it will only append to the end of the sheet. Thank you for the info regarding Filters - I will try and get my head around that. In regards to multiplication, I am using the old google sheets, and the issue I was experiencing has been resolved in the latest version - https://code.google.com/p/google-apps-script-issues/issues/detail?id=1265 – user3213842 Jan 22 '14 at 00:10

1 Answers1

1

I have tested your script, and an functionally identical script in both new and old Google Spreadsheets. I can change the value of a cell in the Source sheet, run the script via the menu, then verify that the same data exists in the Destination sheet.

All of the caching issues listed involve custom functions run in a cell in the spreadsheet. Your script is only being run via a menu or the IDE when actively scripting, and would not meet the criteria for the recalculation issues listed.

You can use FILTER on an IMPORTRANGE, but that doesn't seem to be as 'live':

=FILTER(IMPORTRANGE("key", "Raw Data!A2:E100"),  ImportRange("key", "Raw Data!C2:C100") = "Distributor")

The script that follows is intended for old Google Spreadsheets and works reliably from the IDE or a Menu. Please let me know if it doesn't work for a small data set in two new sheets.

function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [
    {name: "Copy Distributor Rows", functionName: "CopyRowsTest"}
  ];
  ss.addMenu("Copy Rows", menuEntries);
}

function CopyRowsTest() { 
  var source_ss = SpreadsheetApp.getActiveSpreadsheet();
  var target_ss = SpreadsheetApp.openById("xxx");

  var target_sheet = target_ss.getSheetByName("Distributors");
  var source_range = source_ss.getSheetByName("Raw Data").getDataRange();

  var source_values = source_range.getValues();
  var source_formats = source_range.getNumberFormats();

  // Filter the Values
  var filtered_values = source_values.filter(function (row) {

    // Filter your data here
    return row[2] === 'Distributor'; // Column C

  });

  // Append the filtered Values to the target sheet
  filtered_values.forEach(function (row, r) {

    // This will fix any % formatted columns caused by issue 1265
    row = fixPercentFormattedColumns(row, source_formats[r]);

    // Write data to Sheet
    target_sheet.appendRow(row);
  });
}

function fixPercentFormattedColumns(row, rowFormat) {
  return row.map(function (cell, colNum) {
    // Check that the format ends with %, if so return value * 100
    return /%$/.test(rowFormat[colNum]) ? cell * 100 : cell;
  });
}
fooby
  • 851
  • 5
  • 6
  • Thank you very much for all your effort! Tried the script and it is working as expected in new sheets. Only minor issue I have found is if a column in the target sheet has the percentage format applied to it, the data being copied across does not get converted into a percentage properly. E.g. data = 60%. When copied to the target sheet it becomes 0.60% (0.60 in cells with no formatting). If the cell in the target sheet is not formatted, and the data is copied across and then I manually apply the percentage formatting then it becomes 60% - which is correct. – user3213842 Jan 23 '14 at 03:48