google-sheetsgoogle-apps-scriptgoogle-workspace

How to populate a Google Sheet cell with multiple values from data passed from HTML webpage to App Script


I have an HTML website which, when submitted, populates my Google Sheet using my existing App Script. This all works fine but the issue I'm stuck with is in my website, I have a table which allows multiple rows and each row has an input.

enter image description here

This is the data that's posted to my Google Sheet when submitted

Port Main Num=No&Porting Type=PRO&Range Holder=TO POPULATE&Maintain DQ=No&Line Type=Multi&Associated Numbers=01111111111&Associated Numbers Actions=Port&Associated Numbers=02222222222&Associated Numbers Actions=Cease&Associated Numbers=01111122222&Associated Numbers Actions=Port&Title=Mr&Initial=t&Surname=Test&Account Number=01611111111&Company Name=Test Company&Building Name=&Address Line 1=Address Line 1&Address Line 2=&Town or City=Town&Postcode=BB1 1BB&Porting Date=08/10/2024&Main Billing Number=01611111111

But when I check my Google Sheet it only populates with the last number entered (which I did expect)

enter image description here

As you can see from my data, I am passing all 3 numbers so I know I need a loop, but I can't find any relevant information online. The only help I can find is looping cells in the spreadsheet.

This is my current App Script code

const DATA_ENTRY_SHEET_NAME = "Sheet1";
const TIME_STAMP_COLUMN_NAME = "Date";
const REF_COLUMN_NAME = "Ref";
const CUST_EMAIL_COLUMN_NAME = "Email Address";
const PORTING_TIME_COLUMN_NAME = "Porting Time";


var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(DATA_ENTRY_SHEET_NAME);

const doPost = (request = {}) => {
  const { postData: { contents, type } = {} } = request;
  var data = parseFormData(contents);
  appendToGoogleSheet(data);
  
 return ContentService.createTextOutput(contents).setMimeType(ContentService.MimeType.JSON);
};

function parseFormData(postData) {
  var data = [];
  var parameters = postData.split('&');
  for (var i = 0; i < parameters.length; i++) {
    var keyValue = parameters[i].split('=');
    data[keyValue[0]] = decodeURIComponent(keyValue[1]);
  }
  return data;
}

function appendToGoogleSheet(data) {
  if (TIME_STAMP_COLUMN_NAME !== "") {
    data[TIME_STAMP_COLUMN_NAME]=new Date();
  }

  if (sheet.getRange(sheet.getLastRow(), 2).getValue() !== 'Ref') {
    var ref = sheet.getRange(sheet.getLastRow(), 2).getValue().replace("Port-","");
    var ref = parseFloat(ref)+1
    data[REF_COLUMN_NAME]= 'Port-' + ref
  } else {
     data[REF_COLUMN_NAME]='Port-10000'
  }

  if (CUST_EMAIL_COLUMN_NAME !== "") {
    data[CUST_EMAIL_COLUMN_NAME]= 'test@test.co.uk';
  }

  if (PORTING_TIME_COLUMN_NAME !== "") {
    data[PORTING_TIME_COLUMN_NAME]= '10:00';
  }

  var headers = sheet.getRange(5, 1, 1, sheet.getLastColumn()).getValues()[0];
  var rowData = headers.map(headerFld => data[headerFld]);
  sheet.appendRow(rowData);
}

Solution

  • The problem is in your parseFormData function. The line

    data[keyValue[0]] = decodeURIComponent(keyValue[1]);
    

    assigns a value to the keyValue[0] property, replacing any previous value that would exist if there are several form input fields with the same name attribute - as is your case.

    So a possible solution is to check if there already is data with that name, in which case then append the new data to that property. This can be achieved with the ternary operator as follows:

    data[keyValue[0]] = data[keyValue[0]] ?
      data[keyValue[0]].concat(', ', decodeURIComponent(keyValue[1])) :
      decodeURIComponent(keyValue[1]);
    

    My example concatenates the strings with a ', ' separator. Depending on your desired result, you can change that to '\n' or whatever.

    By the way, is there a reason you are using an array to output your data in this function? I believe an object is much more adapted here1. So here's my proposed modified function:

    const postData = "Port Main Num=No&Porting Type=PRO&Range Holder=TO POPULATE&Maintain DQ=No&Line Type=Multi&Associated Numbers=01111111111&Associated Numbers Actions=Port&Associated Numbers=02222222222&Associated Numbers Actions=Cease&Associated Numbers=01111122222&Associated Numbers Actions=Port&Title=Mr&Initial=t&Surname=Test&Account Number=01611111111&Company Name=Test Company&Building Name=&Address Line 1=Address Line 1&Address Line 2=&Town or City=Town&Postcode=BB1 1BB&Porting Date=08/10/2024&Main Billing Number=01611111111";
    
    function parseFormData(postData) {
      var data = {};  // <-- Changed this.
      var parameters = postData.split('&');
      for (var i = 0; i < parameters.length; i++) {
        var keyValue = parameters[i].split('=');
        data[keyValue[0]] = data[keyValue[0]] ?
            data[keyValue[0]].concat(', ', decodeURIComponent(keyValue[1])) :
          decodeURIComponent(keyValue[1]);
      }
      return data;
    }
    
    console.log(parseFormData(postData));

    References


    1An array is, in JavaScript, an object; that is exactly how you were using your data array in your function: adding "hidden" properties to the array.