Home > Blockchain >  Insert timestamp when value paste/edits in whole row in google sheets, only insert to blank cell
Insert timestamp when value paste/edits in whole row in google sheets, only insert to blank cell

Time:01-26

  • I'm trying to insert a timestamp into a cell in the "timestamp" column with the same row index as the edited or pasted value in the "status" column, only insert a timestamp in to an empty cell in "timestamp" column, while skipping the cell that already has a value in the "timestamp" column.

  • I'd also like to convert the date to a number, such as yymmddHHmmss*1000 seri number column "No." Exp: If the timestamp is 22:01:20 14:08:05 and the sequence number in column "No." is 678, then value I want to insert into column "ID" is 2201201408050678.

  • I need to use the column header as a reference in this code to ensure that the function works correctly when the column index changes.

  • Issue: When changing many rows, this code simply repeats the original function for each selected cell. It gets the job done, but not too quickly.

How can I improve code speed when a multi-row update occurs?

No. Timestamp ID Status
20 24:01:22 15:01:30 2201241501300020 Approved
17 Process
16 24:01:22 15:59:10 2201241559100016 Approved
16

function neworder2_onEdit(e) {
  var sheet = e.range.getSheet();
  if ((sheet.getSheetName() == 'RETAIL_ORDER') || (sheet.getSheetName() == 'HAMPER_ORDER') || (sheet.getSheetName() == 'SEA FOOD_ORDER') || (sheet.getSheetName() == 'GARDEN_ORDER'))
  {
  var col = e.range.columnStart;
  var col_header = sheet.getRange(1,col).getValue();
  if (col_header != 'Status') return;

  var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
  var timestamp_col = headers.indexOf('Timestamp')   1;
  var num_col = headers.indexOf('No.')   1;
  var id_col = headers.indexOf('ID')   1;

  var row_start = e.range.rowStart;
  var row_end = e.range.rowEnd;
  if (sheet.getRange(row_start,col).getValue() != 'Approved') return;

  var tz = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
  var timestamp = Utilities.formatDate(new Date(), tz, 'yy-MM-dd HH:mm:ss');

  for (let row = row_start; row <= row_end; row  ) {

    var timestamp_cell = sheet.getRange(row, timestamp_col);
    if (timestamp_cell.getValue() !== '') continue;
    timestamp_cell.setValue(timestamp).setNumberFormat('yy:MM:dd HH:mm:ss');

    var num = sheet.getRange(row,num_col).getValue().toString().padStart(4,'0');
    var id = timestamp.replace(/\D/g,'')   num;
    var id_cell = sheet.getRange(row,id_col);

    id_cell.setValue(id);
  }
  }
}

CodePudding user response:

I believe your goal is as follows.

  • Your script works fine. You want to reduce the process cost of the script.

In this case, how about the following modification?

Modified script:

function neworder2_onEdit(e) {
  var sheet = e.range.getSheet();
  if (['RETAIL_ORDER', 'HAMPER_ORDER', 'SEA FOOD_ORDER', 'GARDEN_ORDER'].includes(sheet.getSheetName())) { // Modified
    var col = e.range.columnStart;
    var col_header = sheet.getRange(1, col).getValue();
    if (col_header != 'Status') return;
    var row_start = e.range.rowStart;
    var row_end = e.range.rowEnd;

    // I modified below script.
    var values = sheet.getRange(row_start, 1, row_end - row_start   1, 4).getValues();
    if (!values.some(r => r[3] == 'Approved')) return;
    var tz = e.source.getSpreadsheetTimeZone();
    var timestamp = Utilities.formatDate(new Date(), tz, 'yy-MM-dd HH:mm:ss');
    var res = values.map(([a, b, c]) => (a == "" || b != "") ? [b, c] : [timestamp, timestamp.replace(/\D/g, '')   a.toString().padStart(4, '0')]);
    sheet.getRange(row_start, 2, row_end - row_start   1, 2).setValues(res);
    sheet.getRange(row_start, 2, row_end - row_start   1, 1).setNumberFormat('yy:MM:dd HH:mm:ss');
  }
}
  • In this modification, after the array was created using the script in your for loop, the array was put to the sheet.

Reference:

Added 1:

From your following replying,

When "status", "ID" or "timstamp" column index change, in case I want to insert column then our code not working. Can we use column header (status, timestamp, ID, No.) as pramameter for my cript? Can you give suggestion to do this?

In this case, how about the following sample script?

Sample script:

function onEdit(e) {
  var sheet = e.range.getSheet();
  if (['RETAIL_ORDER', 'HAMPER_ORDER', 'SEA FOOD_ORDER', 'GARDEN_ORDER'].includes(sheet.getSheetName())) { // Modified
    var col = e.range.columnStart;
    var header = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0].map(h => h.toLowerCase()); // Added
    var obj = header.reduce((o, e, i) => (o[e] = i, o), {});
    var col_header = header[col - 1]; // Modified
    if (col_header != 'status') return;
    var row_start = e.range.rowStart;
    var row_end = e.range.rowEnd;

    // I modified below script.
    var values = sheet.getRange(row_start, 1, row_end - row_start   1, header.length).getValues();
    if (!values.some(r => r[obj["status"]] == 'Approved')) return;
    var tz = e.source.getSpreadsheetTimeZone();
    var timestamp = Utilities.formatDate(new Date(), tz, 'yy-MM-dd HH:mm:ss');
    var res = values.map(r => {
      if (!(r[obj["no."]] == "" || r[obj["timestamp"]] != "")) {
        r[obj["timestamp"]] = timestamp;
        r[obj["id"]] = timestamp.replace(/\D/g, '')   r[obj["no."]].toString().padStart(4, '0');
      }
      return r;
    });
    sheet.getRange(row_start, 1, row_end - row_start   1, res[0].length).setValues(res);
    sheet.getRange(row_start, [obj["timestamp"]]   1, row_end - row_start   1).setNumberFormat('yy:MM:dd HH:mm:ss');
  }
}
  • In this script, from your question, it supposes that the header values are No.,Timestamp,ID,Status. Please be careful this.

Added 2:

From your following new issue,

It's working but there is some issue with my sheet. when scipt ran that paste value to all column, some of theme using arrayformula so all column use arrayformula will get error "#REF!" Can we just paste value to column timestame, id.

In this case, how about the following sample script?

Sample script:

function onEdit(e) {
  var sheet = e.range.getSheet();
  if (['RETAIL_ORDER', 'HAMPER_ORDER', 'SEA FOOD_ORDER', 'GARDEN_ORDER'].includes(sheet.getSheetName())) { // Modified
    var col = e.range.columnStart;
    var header = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0].map(h => h.toLowerCase()); // Added
    var obj = header.reduce((o, e, i) => (o[e] = i, o), {});
    var col_header = header[col - 1]; // Modified
    if (col_header != 'status') return;
    var row_start = e.range.rowStart;
    var row_end = e.range.rowEnd;

    // I modified below script.
    var values = sheet.getRange(row_start, 1, row_end - row_start   1, header.length).getValues();
    if (!values.some(r => r[obj["status"]] == 'Approved')) return;
    var tz = e.source.getSpreadsheetTimeZone();
    var timestamp = Utilities.formatDate(new Date(), tz, 'yy-MM-dd HH:mm:ss');
    var res = values.map(r => {
      if (r[obj["no."]] != "" && r[obj["timestamp"]] == "" && r[obj["status"]] == "Approved") {
        r[obj["timestamp"]] = timestamp;
        r[obj["id"]] = timestamp.replace(/\D/g, '')   r[obj["no."]].toString().padStart(4, '0');
      }
      r.shift();
      return r;
    });
    sheet.getRange(row_start, 2, row_end - row_start   1, res[0].length).setValues(res);
    sheet.getRange(row_start, [obj["timestamp"]]   2, row_end - row_start   1).setNumberFormat('yy:MM:dd HH:mm:ss');
  }
}
  •  Tags:  
  • Related