1

To explain the larger context: there are several forms which generate different sheets. I'm looking for a way to conditionally copy some of the responses sheet to a seperate "Overview" document. Code-wise, I had some ideas for the Overview document, but stranded near the start.

My method was going to be to build functions for all the information I want to retrieve, such as date of birth (example in code block below), date of submission and phone number, when I click on a button. The information may only be copied if the first and surname match the ones in the Overview. The order of the sheets in different docs are not the same and the column length is continually in flux. Furthermore, the amount of rows in the Overview doc is different than the form submission sheets.

In other words: if Anne Annenson would be the twenty-first respondent to a form, I want that information in the overview sheet where they are the first person.

function getDobs() {
    var targetSpreadsheet = SpreadsheetApp.getActive();
    var targetSheet = targetSpreadsheet.getSheetByName("Overview");
    var targetFirstNameCheck = targetSpreadsheet.getRange("A4:A");
    var targetSurnameCheck = targetSpreadsheet.getRange("B4:B"); 
    var sourceSpreadsheetDob = SpreadsheetApp.openById("..."); 
    var sourceDob = sourceSpreadsheetDob.getSheetByName("Form responses 1"); 
    var sourceFirstNameCheckDob = sourceSheetDob.getRange("C2:C"); 
    var sourceSurnameCheckDob = sourceSheetDob.getRange("D2:D"); 
    var sourceRangeDob = sourceSheetDobConsent.getRange("E2:E");

if (sourceFirstNameCheckDob==targetFirstNameCheck && sourceSurnameCheckDob==targetSurnameCheck){ //then I want to copy the data 
    var sourceData = sourceRangePronouns.getValues(); 
    var targetRangeDob = targetSheet.getRange("C4:C");  
 } 
    else (//I want it to leave the cells alone, so any text or formatting that might have been put in manually is still there.){ 
}
}

I would like for the responses to remain in the form response sheets as well.

Any thoughts?

BlueIris
  • 129
  • 1
  • 6
  • getRange() does not return values. You have to use getValues() or getDisplayValues() or even getValue() in the case of a single cell. Both getValues() and getDisplayValues() return a two dimensional array even for a single column or a single row. – Cooper Apr 07 '21 at 15:14
  • The use of ranges like 'A4:A' is highly discouraged because getValues() will return null between the last row and the max rows. I would recommend using sheet.getRange(4,1,sheet.getLastRow()-3,1).getValues() instead. – Cooper Apr 07 '21 at 15:17
  • 1
    I assume that you probably want information from the entire source row I would just get the entire source data all at one time and then loop through the rows making the comparisons that you want and finding the rows that meet your requirements and returning them to the target sheet. Generally, code that takes this approach runs much faster. – Cooper Apr 07 '21 at 15:20

1 Answers1

0

Cooper already explained all the things you need in the comments. And below is what your code would look like following Cooper's comments.

Code

function getDobs() {
  var targetSpreadsheet = SpreadsheetApp.getActive();
  var targetSheet = targetSpreadsheet.getSheetByName("Overview");
  var targetLastRow = targetSheet.getLastRow();
  // range equivalent to A4:B
  var targetNamesCheck = targetSheet.getRange(4, 1, targetLastRow - 3, 2).getValues();

  // tested in same spreadsheet, change "targetSpreadsheet" to openById on your actual script
  var sourceSpreadsheetDob = targetSpreadsheet; 
  var sourceDob = sourceSpreadsheetDob.getSheetByName("Form responses 1");
  var sourceLastRow = sourceDob.getLastRow();
  // range equivalent to C2:D
  var sourceNamesCheckDob = sourceDob.getRange(2, 3, sourceLastRow - 1, 2).getValues();
  // range for data to be copied (E2:G in my sample data)
  var sourceRangeDob = sourceDob.getRange(2, 5, sourceLastRow - 1, 3).getValues();

  var output = [];
  targetNamesCheck.forEach(function (targetNames) {
    // search sourceNamesCheckDob for targetNames 
    var index = searchForArray(sourceNamesCheckDob, targetNames);
    // if targetNames is in sourceNamesCheckDob, save the data on that row for later
    if (index > -1)
      output.push(sourceRangeDob[index]);
    // append blank cells if data is not found
    else
      output.push(new Array(sourceRangeDob[0].length)); 
  });
  // if there were names that were found, write the data beside the targetNames
  if (output.length > 0) {
    targetSheet.getRange(4, 3, output.length, output[0].length).setValues(output);
  }
}

// function to search the array for the object
function searchForArray(haystack, needle) {
  var i, j, current;
  for(i = 0; i < haystack.length; ++i) {
    if(needle.length === haystack[i].length) {
      current = haystack[i];
      for(j = 0; j < needle.length && needle[j] === current[j]; ++j);
      if(j === needle.length)
        return i;
    }
  }
  return -1;
}

Overview:

overview

Form responses 1:

form data

Overview after running getDobs:

output

EDIT:

Since there are no methods that includes the apostrophe when the cell value is being fetched, easiest way is to have the sheets identify the phone number as text so it won't remove the 0 in the beginning. I've thought of 3 ways to have the 0 included in the output:

  • Add the apostrophe manually on the specific output column via script
  • Add dashes on the number so it is treated as text (09395398314 -> 093-9539-8314) (just an example, not sure if that is the right format)
  • Format the output column into number -> plain text instead of number -> automatic

I prefer formatting the output column as that will be the fastest and easiest thing to do.

Format:

format

Output:

Output

Note:

  • This function will fill up rows where names in Overview are present in Form responses 1.

References:

NightEye
  • 10,634
  • 2
  • 5
  • 24
  • 1
    Thank you, that was really helpful. Phone numbers here often start with a 0, any idea how to copy along the apostrophe that indicates to Sheets that the naught should be shown? – BlueIris Apr 08 '21 at 13:38
  • Hi @BlueIris, I have updated my answer above for the fix on 0 for phone numbers. If we answered your question, please click the accept button. By doing so, other people in the community, who may have the same concern as you, will know that theirs can be resolved. If the accept button is unavailable to you, feel free to tell me. stackoverflow.com/help/accepted-answer – NightEye Apr 08 '21 at 15:31