0

I am trying to create an event to trigger on form submit. I have been using this script below and it has been working fantastically. However, each time the response is edited, it duplicates the row. After researching, I know I need to move the script to be attached to the form instead of the spreadsheet. I am very new to apps script and can't figure out how to change the script to work from the form.

function timerEvent(e){
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sourceSheet = e.range.getSheet();
    if(sourceSheet.getSheetName() === 'Form Responses'){
        var row = e.range.getRow();
        var rowRange = sourceSheet.getRange(row, 1, 1, sourceSheet.getLastColumn());
        var rowValues = rowRange.getValues()[0];
        if(rowValues[21]!= ""&&rowValues[17]!="Yes"){
            var targetSheet = ss.getSheetByName("UENA");
            targetSheet.insertRowBefore(2);  
            var targetRange = targetSheet.getRange(2, 4);
            rowRange.copyTo(targetRange);
  targetSheet.getRange('4:4').copyTo(targetSheet.getRange('2:2'), SpreadsheetApp.CopyPasteType.PASTE_CONDITIONAL_FORMATTING, false);
  targetSheet.getRange('4:4').copyTo(targetSheet.getRange('2:2'), SpreadsheetApp.CopyPasteType.PASTE_FORMAT, false);
  targetSheet.getRange("A2:AD").sort([{column: 8, ascending: true}, {column: 7, ascending: true}]);
        targetSheet.getRange('B2').setDataValidation(SpreadsheetApp.newDataValidation()
          .setAllowInvalid(false)
          .requireValueInList(['AA', 'BB', 'CC', 'DD', 'EE', 'FF', 'GG', 'HH', 'II', 'KK', 'LL'], true)
          .build());
        targetSheet.getRange('C2').insertCheckboxes();    

        }     
    } 
} 
10
  • Hi. Would "After researching, I know I need to move the script to be attached to the form instead of the spreadsheet. " Would you please cite a reference for this. Commented Jan 25, 2023 at 10:52
  • Hi and welcome. It would be helpful if you describe the EXACT scenario that you are trying to resolve; at the moment you are describing a technical issue but you haven't explained WHY this is an issue. Possibly you have a form linked to a spreadsheet but form users are allowed to edit their responses which means that the spreadsheet would have one row for the initial response, and another row for the edited response. Commented Jan 25, 2023 at 10:59
  • Hi! Thank you so much for your prompt response! Currently, I have the above code in a script attached to the spreadsheet where the form responses get sent to. If the user edits the response, this script is triggered again. This creates a duplicate row. I may be completely off base and cannot currently find where I read about attaching the script to the Form instead of the Spreadsheet. What I want to happen: if the form is edited, the row is updated on both the responses page (sourceSheet) AND the 'UENA' page (targetSheet) without duplicating. Is this even possible or am I chasing a dream? haha Commented Jan 25, 2023 at 11:20
  • "However, each time the response is edited, it duplicates the row." Is Allow response editing set to On? Would you please describe any other relevant form settings and the process by which a user can edit their response. (if the user selects "Edit your response" immediately after submitting the form, then the response is not duplicated.) Commented Jan 25, 2023 at 11:22
  • I want to set "Allow response editing" to On. However, when I do and the user selects "Edit your response", the OnFormSubmit trigger is activated again and the response is duplicated in the spreadsheet. Commented Jan 25, 2023 at 11:27

1 Answer 1

1

You have a spreadsheet linked to a Google Form and responses are recorded in the spreadsheet. You have a function installed as an Installable onFormSubmit trigger; this function makes a duplicate of each response in a second sheet. But... users have the ability to edit their submissions. Though the entry on the response sheet is not duplicated (the existing response row is editted), your function is triggered by the response and a duplicate entry is inadvertently made on the target sheet.


Solution#1

The solution to this problem is found in how Google Sheets treats an edited response. When an edited response is submitted a Note is inserted in the edited cell. So, one tests for whether there are any Notes in the response range. The response range can be identified by using Event Objects.

When the response is copied to "UENA" sheet, it is inserted at the top of the page, and then (later) the data is sorted by two other columns. This makes it impossible to write a copyTo command that accurately reflects the location of the original submission on UENA.

However, the following snippet shows the code that would be used if the destination on UENA was predictable.


function timerEvent(e){

  var ss = SpreadsheetApp.getActiveSpreadsheet()
  var sourceSheet = ss.getSheetByName("Form Responses 1")

  // use this to show all the Event Objects  
  Logger.log(JSON.stringify(e)) // DEBUG

  // get the response range using Event Objects
  var respRange = e.range
  Logger.log("DEBUG: the response range = "+respRange.getA1Notation())

  // get any notes in the response range and flattened into a 1d array
  var notes = respRange.getNotes()
  var flatNotes = notes.flat()
  Logger.log(flatNotes) // DEBUG
  
  // test whether any notes exist
  var found = flatNotes.find(element => element.length > 0)
  // if undefined, then there are no notes
  if (found === undefined){
    Logger.log("DEBUG: This is an original submission")
    // insert relevant code to copy response to target
  }
  else{
    Logger.log("DEBUG: this is an edited submission. The edited row is "+e.range.rowStart)
    var respLR = sourceSheet.getLastRow()
    Logger.log("DEBUG: last row: "+respLR)
    var rowDiff = respLR-e.range.rowStart
    var targetSheet = ss.getSheetByName("UENA")
    var targetStartRow = 2
    var targetEditRange = targetSheet.getRange(rowDiff+targetStartRow,4)
    Logger.log("DEBUG: target"+targetEditRange.getA1Notation())

    // copy to UENA
    // can't use this line since the original submission has been sorted
    //respRange.copyTo(targetEditRange) 
    
    }
}

Solution#2

There is a second solution.

Instead of copying each response one-by-one, as they are received, copy the entire range from the response sheet whenever a single response is received. This will ensure that there are no duplicates on UENA, and also that the sort order on UENA is retained.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.