0
votes

Need help on combining these two script. Im totally newbie in this thing. They are

Main.gs

whenput 'XX' on U Column (21st col) then it copy the whole row to a sheet with same name as V Column (22nd col). Then it delete certain columns (for example 6, 7, 8, 12,14,16,17,19,20,21)

function onEdit(e) {

var ss = e.source;
var s = e.range.getSheet();;
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 21;
var nameCol = 22;
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to ok do stuff
if (e.value == "XX" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) { 
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.' 
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
  s.getRange(rowIndex, col).clearContent();
}

// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}

and TimeStamp.gs

when type a word at "Pasien" Col, at the same row it will add date to "Tgl Keluar" col and when delete that word, it also clear content

function onEdit(event)
{ 
  var timezone = "GMT+7";
  var time_format = "dd-MM-yyyy"; // Timestamp Format. 
  var updateColName = "Pasien";
  var timeStampColName = "Tgl Keluar";
  var sheet = event.source.getSheetByName('Form'); //Name of the sheet where you want to run this script.

  var actRng = event.source.getActiveRange();
  var editColumn = actRng.getColumn();
  var index = actRng.getRowIndex();
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
  var dateCol = headers[0].indexOf(timeStampColName);
  var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
 
  if (dateCol > -1 && index > 1 && editColumn == updateCol) 
  
  { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
  
  if (sheet.getRange(index, updateCol).isBlank()) {
  sheet.getRange(index, dateCol + 1).clearContent();
}
else 
    var cell = sheet.getRange(index, dateCol + 1);
    var date = Utilities.formatDate(new Date(), timezone, time_format);
    cell.setValue(date);
  }
}

This my combined onEdit but i still dont understand about nested

function onEdit(event) {
  first(event);
  second(event);
}

function first(event) 
{

var ss = e.source;
var s = e.range.getSheet();;
if (s.getName() !== 'Form')
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 21;
var nameCol = 22;
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to ok do stuff
if (e.value == "XX" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) { 
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.' 
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
  s.getRange(rowIndex, col).clearContent();
}

// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}

function second(event)
{ 
  var timezone = "GMT+7";
  var time_format = "dd-MM-yyyy"; // Timestamp Format. 
  var updateColName = "Pasien";
  var timeStampColName = "Tgl Keluar";
  var sheet = event.source.getSheetByName('Form'); //Name of the sheet where you want to run this script.

  var actRng = event.source.getActiveRange();
  var editColumn = actRng.getColumn();
  var index = actRng.getRowIndex();
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
  var dateCol = headers[0].indexOf(timeStampColName);
  var updateCol = headers[0].indexOf(updateColName); updateCol = updateCol+1;
 
  if (dateCol > -1 && index > 1 && editColumn == updateCol) 
  
  { // only timestamp if 'Last Updated' header exists, but not in the header row itself!
  
  if (sheet.getRange(index, updateCol).isBlank()) {
  sheet.getRange(index, dateCol + 1).clearContent();
}
else 
    var cell = sheet.getRange(index, dateCol + 1);
    var date = Utilities.formatDate(new Date(), timezone, time_format);
    cell.setValue(date);
  }
}

2
All scripts need to have a unique nameCooper
i dont understand how things work and need them badlyyoenoess
Then I recommend hiring someone to help or learn quickly.Cooper
For the start try to change first(event) by function first(event), and second(event) by function second(event). I don't know but there is a chance that the third example will work.Yuri Khristich
The problem might be that with the two functions the code does not complete in 30 seconds which is a requirement. Perhaps you should reduce the size of you code by learning how to take more advantage of the event object.Cooper

2 Answers

2
votes

The third code would be the simplest solution in case it complete within the time limit.

Otherwise, you need to optimize the code by:

  • replacing call of SpreadsheetApp by event object
  • removing duplicates among the two child functions
  • using if, boolean (flag), return to minimize executions

You need to know you code well in other to do either of these.

1
votes

I dare not rewrite the code entirely. Just in order to make it a bit faster I'd propose to change this lines (in the third example):

const cols = [6, 7, 8, 12,14,16,17,19,20,21];
for (const col of cols) {
  s.getRange(rowIndex, col).clearContent();
}

to this:

// cols to clean
const cols = [6, 7, 8, 12, 14, 16, 17, 19, 20, 21];

// get an array from the row
var row_to_clean = s.getRange(rowIndex, 6, rowIndex, 21).getValues();

// clean the array
for (let c of cols) row_to_clean[0][c-6] = ''; // col 6 is array[0][0]

// set values of the array back on the row
s.getRange(rowIndex, 6, rowIndex, 21).setValues(row_to_clean);

It will reduce calls to the server from 10 clearContents() to 2 getValues() + setValues() for every edited row.