The program that I have posted is already working which does the following :
newOpex(), newMBAP(), and newCashDR() are functions that create a copy of their respective sheets which are copied from a template sheet named templateOpex, templateMBAP, and templateCashDR which is within the spreadsheet. The template sheet is basically an empty form of the sheet of each which is RCDisb (OpEx) : Current, RCDisb (MBAP) : Current, and CashDR : Current. When any of the 3 functions is called, It changes the name of the sheet to its respective number ( Ex.from RCDisb (OpEx) : Current to RCDisb (OpEx) : Sheet #1 ) and changes the newly made sheet to Current.
When the function resetSCA() is called, it copies the spreadsheet into a folder in Google Drive and deletes the sheets inside the Spreadsheet and reproduces a fresh copy of templateOpex, templateMBAP, and templateCashDR ready to be used by the user again.
Now my issue is that, I can't seem to find a way to delete the sheets including the ones that were just added without it touching the DV Logbook and the other Template sheets and without the code failing due to null which is caused by the newly added sheets.
const ws = SpreadsheetApp.getActiveSpreadsheet()
const ws_lb = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DV Logbook");
const ws_opex = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RCDisb (OpEx) : Current");
const ws_mbap = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RCDisb (MBAP) : Current");
const ws_cashdr = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CashDR : Current");
//lastrow_indicators
const lastrow_lb = ws_lb.getLastRow();
const lastrow_opex = ws_opex.getLastRow();
const lastrow_mbap = ws_mbap.getLastRow();
const lastrow_cashdr = ws_cashdr.getLastRow();
function newOpex(){
var ui = SpreadsheetApp.getUi();
var rcdisbopex = 1;
var result = ui.prompt(
'📄 Create New Operating Expense Sheet',
'Please enter Sheet Number:',
ui.ButtonSet.OK_CANCEL);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText()
if (button == ui.Button.OK) {
// User clicked "OK".
var newOpexName = SpreadsheetApp.getActive().getSheetByName("RCDisb (OpEx) : Current").setName("RCDisb (OpEx) : Sheet #"+ rcdisbopex);
var newOpexSheet = newOpexName.getSheetName();
Logger.log(newOpexSheet);
rcdisbopex++;
var templateSheet = SpreadsheetApp .getSheetByName('templateOpEx');
ws.insertSheet('RCDisb (OpEx) : Current', 2, {template: templateSheet});
var sheetName = ('RCDisb (OpEx) : Current');
Logger.log(sheetName);
Utilities.sleep(1000)
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert('⚠️Operation Cancelled.');
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert('⚠️You closed the dialog.');
}
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
ss.getRange(9, 8, 1, 1).setValue(text)
ss.getRange(8, 8, 1, 1).setValue(text)
ss.getRange(5, 6, 1, 1).setValue("Period Covered: "+ date)
}
function newMBAP(){
var ui = SpreadsheetApp.getUi();
var rcdisbmbap = 1;
var result = ui.prompt(
'📄 Create New Medical and Burial Assistance Sheet',
'Please enter Sheet Number:',
ui.ButtonSet.OK_CANCEL);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText()
if (button == ui.Button.OK) {
// User clicked "OK".
var newMBAPName = SpreadsheetApp.getActive().getSheetByName("RCDisb (MBAP) : Current").setName("RCDisb (MBAP) : Sheet #"+ rcdisbmbap);
var newMBAPSheet = newMBAPName.getSheetName();
Logger.log(newMBAPSheet);
rcdisbmbap++;
var templateSheet = SpreadsheetApp.getSheetByName('templateMBAP');
ws.insertSheet('RCDisb (MBAP) : Current', 4, {template: templateSheet});
var sheetName = ('RCDisb (MBAP) : Current');
Logger.log(sheetName);
Utilities.sleep(1000)
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert('⚠️Operation Cancelled.');
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert('⚠️You closed the dialog.');
}
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
ss.getRange(9, 8, 1, 1).setValue(text)
ss.getRange(8, 8, 1, 1).setValue(text)
ss.getRange(5, 6, 1, 1).setValue("Period Covered: "+ date)
}
function newCashDR(){
var ui = SpreadsheetApp.getUi();
var cashdrNum = 1;
var result = ui.prompt(
'📄 Create New Cash Disbursements Record Sheet',
'Please enter Sheet Number:',
ui.ButtonSet.OK_CANCEL);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText()
if (button == ui.Button.OK) {
// User clicked "OK".
var newCashDRName = SpreadsheetApp.getActive().getSheetByName("CashDR : Current").setName("CashDR : Sheet #"+ cashdrNum);
var newCashDRSheet = newCashDRName.getSheetName();
Logger.log(newCashDRSheet);
cashdrNum++;
var templateSheet = SpreadsheetApp.getSheetByName('templateCashDR');
ws.insertSheet('CashDR : Current', 6, {template: templateSheet});
var sheetName = ('CashDR : Current');
Logger.log(sheetName);
Utilities.sleep(1000)
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert('⚠️Operation Cancelled.');
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert('⚠️You closed the dialog.');
}
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
ss.getRange(8, 9, 1, 1).setValue(text)
}
function resetSCA(){
var destFolder = DriveApp.getFolderById("14NSBP1OFTPtY8xdV7IIo2m7GNRBAeJDQ");
DriveApp.getFileById("1h3rg7rqmteYAnVFSAzIS-hr5bbnwgRFitIDhZp5javo").makeCopy(date + "_SCA_DavaoDisbursements", destFolder);
ws_lb.deleteRows(2, 100);
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
if (sheets[4] == sheets){
ws.deleteSheet(sheets[4]);
} else if (sheets[5] == sheets){
ws.deleteSheet(sheets[5]);
} else if (sheets[6] == sheets){
ws.deleteSheet(sheets[6]);
} else if (sheets[7] == sheets){
ws.deleteSheet(sheets[7]);
} else if (sheets[8] == sheets){
ws.deleteSheet(sheets[8]);
} else if (sheets[9] == sheets){
ws.deleteSheet(sheets[9]);
}
var templateSheetopex = ws.getSheetByName('templateOpEx');
var templateSheetmbap = ws.getSheetByName('templateMBAP');
var templateSheetcashdr = ws.getSheetByName('templateCashDR');
ws.insertSheet('RCDisb (OpEx) : Current', 2, {template: templateSheetopex});
ws.insertSheet('RCDisb (MBAP) : Current', 3, {template: templateSheetmbap});
ws.insertSheet('CashDR : Current', 4, {template: templateSheetcashdr});
}
I can't seem to really find a method that really fits the problem. I would especially be interested in methods that can simplify the process of the code.
Extra information about the code: the code uses Custom Menus and sub-menus while the input is placed through a Google Form.
I have reproduced a whole working sample of the code for your reference except for the resetSCA() as I can't reproduce a sample of the Google Drive for readers to see.
Code sample: https://docs.google.com/spreadsheets/d/1Z7N__RHwxK1Xp9YMUxA4sMq37U8TiCMiD39jTFP0Zxg/edit?usp=sharing
I believe your goal is as follows.
About the active Spreadsheet, you want to delete the sheets RCDisb (OpEx) : Current, RCDisb (MBAP) : Current, CashDR : Current, and if already generated, RCDisb (OpEx) : Sheet #1, RCDisb (MBAP) : Sheet #1, CashDR : Sheet #1.
And, you want to copy the sheets templateOpex, templateMBAP, templateCashDR
From your showing script and your provided Spreadsheet, you want to rename the copied sheets from templateOpex, templateMBAP, templateCashDR to RCDisb (OpEx) : Current, RCDisb (MBAP) : Current, CashDR : Current, respectively. And, you want to set the sheets to the index of 1, 2, and 3.
If my understanding is correct, how about the following sample script?
Sample script:
function sample() {
const deleteSheetNames = ["RCDisb (OpEx) : Current", "RCDisb (MBAP) : Current", "CashDR : Current", "RCDisb (OpEx) : Sheet #1", "RCDisb (MBAP) : Sheet #1", "CashDR : Sheet #1"];
const copySheetNames = [{ copy: "templateOpex", name: "RCDisb (OpEx) : Current", index: 1 }, { copy: "templateMBAP", name: "RCDisb (MBAP) : Current", index: 2 }, { copy: "templateCashDR", name: "CashDR : Current", index: 3 }];
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Delete sheets.
deleteSheetNames.forEach(name => {
const sheet = ss.getSheetByName(name);
if (!sheet) return;
ss.deleteSheet(sheet);
});
// Copy sheets.
copySheetNames.forEach(({ copy, name, index }) => {
const sheet = ss.getSheetByName(copy);
if (!sheet) return;
ss.insertSheet(name, index, { template: sheet });
});
}
About your script resetSCA(), sheets of var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets(); is an array. But, in your script, Class Sheet object is compared with an array including Class Sheet objects at sheets[4] == sheets. I thought that this might be your current issue.
When this script is run, I thought that the above goal is achieved.
Note:
If you want to change the index of the copied sheet, please modify copySheetNames.
If you are required to use the following script, please add it to top of the above function.
var destFolder = DriveApp.getFolderById("14NSBP1OFTPtY8xdV7IIo2m7GNRBAeJDQ");
DriveApp.getFileById("1h3rg7rqmteYAnVFSAzIS-hr5bbnwgRFitIDhZp5javo").makeCopy(date + "_SCA_DavaoDisbursements", destFolder);
ws_lb.deleteRows(2, 100);
Reference:
forEach()
So I have an archiver I am using from another project, to make an archived copy of the contents of a spreadsheet, sheet by sheet. My problem is, that archiver was used to get all of the sheets of the spreadsheet for the other project. For this project, I only want certain sheets to be in the array of sheets (not all of them). How can I modify this function to do that? I've tried a few approaches but they always screw up the map function. Any help would be appreciated, thank you.
function Archive() {
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.prompt(
'What would you like to call this file?',
'Please enter file name:',
ui.ButtonSet.OK_CANCEL);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
var spreadsheetId = "Spreadsheet ID"; // Please set the source Spreadsheet ID.
var destFolderId = "Target Folder ID"; // Please set the destination folder ID.
// Copy each sheet in the source Spreadsheet by removing the formulas as the temporal sheets.
var ss = SpreadsheetApp.openById(spreadsheetId);
var arraysheets = ["Budget Input","Budget (Universal)","Covid Parameters"]
var tempSheets = ss.getSheets().map(function(sheet) {
var dstSheet = sheet.copyTo(ss).setName(sheet.getSheetName() + "_temp");
var src = dstSheet.getDataRange();
src.copyTo(src, {contentsOnly: true});
return dstSheet;
});
// Copy the source Spreadsheet.
var destination = ss.copy(text);
// Delete the temporal sheets in the source Spreadsheet.
tempSheets.forEach(function(sheet) {ss.deleteSheet(sheet)});
// Delete the original sheets from the copied Spreadsheet and rename the copied sheets.
destination.getSheets().forEach(function(sheet) {
var sheetName = sheet.getSheetName();
if (sheetName.indexOf("_temp") == -1) {
destination.deleteSheet(sheet);
} else {
sheet.setName(sheetName.slice(0, -5));
}
});
// Move file to the destination folder.
var file = DriveApp.getFileById(destination.getId());
DriveApp.getFolderById(destFolderId).addFile(file);
file.getParents().next().removeFile(file);
ui.alert('Your file name is recorded as ' + text + '.');
}
if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert('Operation Cancelled');
}
if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert('You closed the dialog.');
}
}
Just remove the Sheets that you don't want to copy before running the map function. For example if you don't want to include Sheets 1, 3 and 5 you would do it like this:
var sheets = ss.getSheets();
// remove sheet one which is at index 0
sheets.splice(0, 1);
// remove sheet three which was at index 2 but now the array does not have
// sheet one so it will be at index 1
sheets.splice(1,1);
// remove sheet 5 which was at index 4 but now it is at index 2 as we removed 2 sheets
sheets.splice(2,1);
var tempSheets = sheets.map(function(sheet) {
// ...
References
Splice
I'm trying to create a script that will copy a range of data from one sheet to two other separate sheets when a user clicks "Yes" in the alert message. One of those two will be on a new spreadsheet created using a template. The data I want to copy is from a sheet called "data". The destination sheets are named "selected" and on the new spreadsheet, "csv". The new spreadsheet will be stored in a different folder. Found this [script][1] to be very helpful for me to get started.
The onEdit script is working fine for the "data" sheet and transfers the chosen row to the "selected" sheet when a user clicks the checkbox and the "Yes" button in the alert message.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "data" && r.getColumn() == 16 && r.getValue() == "Yes") {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Are you sure you want to continue?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("selected");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
Logger.log('The user clicked "Yes."');
}
else if (response == ui.Button.NO) {
clearAnswer();
Logger.log('The user clicked "No" or the close button in the dialog\'s title bar.');
}
}
First issue I have is that the condition else if is not triggering the function "clearAnswer" when a user clicks NO in the alert message even though the function works when triggered in the script editor.
function clearAnswer() {
var app = SpreadsheetApp;
var clearSheet = app.getActiveSpreadsheet().getActiveSheet();
clearSheet.getRange("P2:P").clearContent();
}
Second issue is I don't know where to begin with the script that will copy the chosen row from the "data" sheet to the "csv" sheet on a new spreadsheet which will be created using a template. I found this script so far.
// Pull spreadsheet template
var ss = SpreadsheetApp.openById('TEMPLATEFILEID');
var newSS = ss.copy("Copy of " + ss.getName());
// Move to original folder
var targetFolder = DriveApp.getFileById('FOLDERFORNEWFILE');
var newSSFile = DriveApp.getFileById(newSS.getId());
originalFolder.addFile(newSSFile);
DriveApp.getRootFolder().removeFile(newSSFile);
}*/
I would appreciate any help you can give me or I hope you can point me to the right direction so I can figure things out faster.
You else if is nested outside of the popup event. Try like this:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "data" && r.getColumn() == 16 && r.getValue() == "Yes") {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Are you sure you want to continue?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("selected");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
Logger.log('The user clicked "Yes."');
} else if (response == ui.Button.NO) {
clearAnswer();
Logger.log('The user clicked "No" or the close button in the dialog\'s title bar.');
}
}
}
}
I am writing to find ways to capture the Google Sheet column headers and a specific column value for the given row.
I have a code where I am recording a changelog into a new sheet. See below:
// This script records changes to the spreadsheet on a "Changelog" sheet.
// The changelog includes these columns:
// "Timestamp", "Sheet", "Cell", "Type", "Old Value", "New Value", "User"
// Users are logged by email address.
// Source 1: https://productforums.google.com/d/topic/docs/az365_ypIV0
// Source 2: https://productforums.google.com/forum/#!topic/docs/AI9OxbOtvWE
// Source 3: http://eyana.me/create-a-simple-changelog-using-google-apps-scripts
function onEdit(e) {
var changelogSheetName = "Changelog";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = SpreadsheetApp.getActiveRange();
var timestamp = new Date();
var currentSheet = ss.getActiveSheet();
var currentSheetName = currentSheet.getName();
var HRISmaster = "HRIS Master";
var previousValue = e.oldValue;
var newValue = cell.getValue();
var typeChange = "Change";
// if it is the changelog sheet that is being edited, do not record the change to avoid recursion
if (currentSheetName == changelogSheetName || currentSheetName !== HRISmaster) return;
var changelogSheet = ss.getSheetByName(changelogSheetName);
if (changelogSheet == null) {
// no changelog sheet found, create it as the last sheet in the spreadsheet
changelogSheet = ss.insertSheet(changelogSheetName, ss.getNumSheets());
Utilities.sleep(2000); // give time for the new sheet to render before going back
ss.setActiveSheet(currentSheet);
changelogSheet.getRange('A1:G1').setBackground('#E0E0E0');
changelogSheet.appendRow(["Timestamp", "Sheet", "Cell", "Type", "Old Value", "New Value", "User"]);
changelogSheet.deleteColumns(8,19);
changelogSheet.setFrozenRows(1);
changelogSheet.setColumnWidth(1, 170);
changelogSheet.setColumnWidth(7, 170);
changelogSheet.protect();
}
var user = Session.getEffectiveUser().getEmail();
if (previousValue == null){
typeChange = "Set";
} else if (newValue == "") {
typeChange = "Unset";
}
changelogSheet.appendRow([timestamp, currentSheetName, cell.getA1Notation(), typeChange, previousValue, newValue, user]);
}
Now I need to figure a way out to grab the column header and not the cell reference where the change is made and the column value where I have some IDs stored in the same sheet.
I have prepared a sample sheet with dummy data which is exactly the same as the real data I have. The sheet can be found here https://docs.google.com/spreadsheets/d/1sMthpSG-7L-uv7XssQ9UO2FU2o385aekEwhHmb9-1Lk/edit?usp=sharing
I have added an additional sheet (Need this type of Changelog) that shows the kind of changelog I need.
Can someone please help.
Best Regards,
Syed H
Why not extract them directly using range location?
var field = currentSheetName.getRange(1, cell.getColumn()).getValue();
var id = currentSheetName.getRange(cell.getRow(), 1).getValue();
changelogSheet.appendRow([timestamp, field, id, currentSheetName, cell.getA1Notation(), typeChange, previousValue, newValue, user]);
Pardon me as I am fairly new to this and may be missing something easy.
I have a spreadsheet that I create data from a template, run a script over it to create forms which become user tasks. The edit URL from the form is used to complete the task and it records on the master sheet (Sheet2) with the status, attachments, data stamp, and email address. From there I am trying to create a list of tasks that need approvals from my master sheet to another sheet (LOG) on a different spreadsheet but I am having issues with openByID for my target spreadsheet. It says it is undefined. I can get this to work in sheets in the same spreadsheet but I would like it in a different spreadsheet if possible. This is all done onChange of Sheet2 when status changes to yes and only for specific tasks (Verification Report, Maintenance Memo, Check Report)
function onChange() {
// moves a row from one sheet to another sheet when a value is entered in a column and another column has specific values
var columnNumberToWatch = /* column D */ 4; // column A = 1, B = 2, etc.
var valueToWatch = "yes";
var sheetNameToMoveTheRowTo = "LOG";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var cell = sheet.getActiveCell();
var activeRow = cell.getRow();
var taskCheck=sheet.getRange(activeRow, 2);
var target = SpreadsheetApp.openByID("my spreadsheet id");
var targetSheet = target.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
if (sheet.getName() != sheetNameToMoveTheRowTo &&
cell.getColumn() == columnNumberToWatch &&
cell.getValue().toLowerCase() == valueToWatch &&
(taskCheck.getValue() == "Verfication Report" || taskCheck.getValue() == "Maintenance Memo" || taskCheck.getValue() == "Check Report"))
{
sheet.getRange(cell.getRow(), 1, 1, sheet.getLastColumn()).copyTo(targetRange);
}
}