I was wondering if someone could offer me some advice.
I have a master spreadsheet, acting as a template. I have written a script which can be run from the menu (using addToUi command), which makes a copy of template spreadsheet.
The problem is that the script gets copied into the new spreadsheet also which I don't want.
Could anyone suggest a possible way around this please?
I did think a possible way was to get the script to open the copied template and delete the script but not sure if this is possible.
Here is the function which does the copying....
function createCopy() {
var myValue = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("B8").getValue();
var destinationFolder = DriveApp.getFolderById("xxxxxxxxxxxxxxxx");
DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).makeCopy(myValue,destinationFolder);
}
(Cell reference B8 holds the value of what I called the copied spreadsheet).
Rayden, I use a function like that to just copy one sheet to a new spreadsheet and it doesn't drag the script with it. gDrive is the id for the Spreadsheet, tabName the individual sheet you want copied, Filename the name of the copy and destination the destination directory.
//******************************************************************************
//- This function takes a tab and makes it its own file
function tabToSheet(gDrive,tabName,fileName,destination){
var sh = SpreadsheetApp.openById(gDrive);
var ss = sh.getSheetByName(tabName);
//create a new document in the location given
var newSheet = SpreadsheetApp.create("TEMPDELETEME");
//copy the tab from current document to new document
ss.copyTo(newSheet);
var id = newSheet.getId();
newSheet.deleteSheet(newSheet.getSheetByName("Sheet1"));
os = newSheet.getSheets()[0];
os.setName(tabName);
var file = DriveApp.getFileById(id);
var folder = DriveApp.getFolderById(destination);
var finalId = file.makeCopy(fileName, folder).getId();
file.setTrashed(true);
return finalId;
}//*****************************************************************************
The difference is that i'm making a new sheet, then copying the tab rather than copying the entire file. You could add another tab and remove the variables if you want to copy multiple tabs.
I was having trouble implementing J.G.'s approach of moving individual sheets, so the approach I took was to add a conditional in front of the script to only run if the spreadsheet id was equal to the id of the original spreadsheet. My use case was trying to suppress a custom menu on the original workbook from reappearing on the copy, so it worked for that.
var bookId = spreadsheet.getId();
if (bookId === 'original spreadsheet id') {
*Function*
}
Related
We are using sheets for our mom & pop store as our invoice. However, my mother-in-law keeps saving over our invoice and we're always having to go back and delete the filled in sections. She cannot seem to remember the steps of making a copy and then opening that. I am using a script (button) to create a copy of the original and it is renamed as the customer name & date into a specific folder. However, once we do that, we still have to navigate to the folder and open the new document. Is there there a way to do this after I click the button on our original document to open of the copy that was made? Here is the script that I am using.
function saveAsSpreadsheet()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var range = sheet.getRange('Carolina Fireworks Order Form!C8');
sheet.setNamedRange('TestRange', range);
var TestRange = sheet.getRangeByName('Carolina Fireworks Order Form!C8').getValues();
Logger.log(TestRange);
var destFolder = DriveApp.getFolderById("1UdK90fEs3gkP4KZuUbmZbvvyVAW5ZMGw");
let name = SpreadsheetApp.getActiveSheet().getRange('C8').getValue();
const ds = Utilities.formatDate(new Date(),SpreadsheetApp.getActive().getSpreadsheetTimeZone(),"MM.dd.yy");
DriveApp.getFileById(sheet.getId()).makeCopy('TestRange', destFolder).setName(`${name}.${ds}`);
}
In your situation, how about the following modification?
From:
DriveApp.getFileById(sheet.getId()).makeCopy('TestRange', destFolder).setName(`${name}.${ds}`);
To:
const file = DriveApp.getFileById(sheet.getId()).makeCopy('TestRange', destFolder).setName(`${name}.${ds}`);
var js = `<script>window.open('${file.getUrl()}');google.script.host.close();</script>`;
var html = HtmlService.createHtmlOutput(js);
SpreadsheetApp.getUi().showModalDialog(html, 'Now loading.');
In this script, the URL is opened using Javascript on the dialog.
This is from this post
Note:
From MetaMan's comment
If you want this to work you will have to disable popup blocking
References:
showModalDialog(userInterface, title)
Window.open()
I need a way to open a spreadsheet only by having the name of the corresponding file and the folder where the file is located. What I'm trying to do is creating a temporary copy of an active spreadsheet and reading information from the copy file rather than the active one. But unfortunately this copy file won't have a constant ID and URL as it's going to be erased every time after the script is done, and re-created with the next running of the script.
What I already tried is using the URL of the temporary file in order to open the spreadsheet itself, as you can see below.
But it's not useful for me, as I don't have a constant URL of this file (as it will be erased in the end of the script and have a new URL with the next script). But I have a constant name of the file, as well as this will be the only file in the respective folder.
What I also tried is looking for methods to open file only using its name (which is "temp_copy" in a 'temp_folder'). But I didn't find a working solution.
var report = SpreadsheetApp.getActiveSpreadsheet();
var temp_folder =
DriveApp.getFolderById("1EAsvVcFjIw5iGTeF_SxxQJLVlaLHl_pR");
DriveApp.getFileById(report.getId()).makeCopy("temp_copy", temp_folder);
var temp_copy = SpreadsheetApp.openByUrl(' ');
var hiddenSheet = temp_copy.getSheetByName('DATE');
var lastRow = hiddenSheet.getSheetValues(1,1,1,1);
var sheet = temp_copy.getSheetByName('forCSV');
var lastColumn = sheet.getLastColumn();
var activeRange = sheet.getRange(1,2,lastRow,lastColumn);
What I'm expecting as a result is to make the link between the 3rd line of the code (when making a copy of the basic file) and 5th line of the code onwards (when referencing specific range from the temporary file) only by using name of the file or respective folder. In theory it seems so easy, I should be missing something somewhere...
Many thanks in advance!
You can use DriveApp to get a FileIterator which contains the Sheet.
var file, files = DriveApp.getFilesByName("temp_copy");
if (files.hasNext ()){
file = files.next(); // Get first result for name
} else {
return "";
}
var sheet = SpreadsheetApp.openById(file.getId())
I basically am imagining commands that would change the sharing status of sheets it was allowed to edit. For example, I have a master document for a company (a "Roster" for keeping track of where employees are working and which other employees they are working with in that area) and other "Area Sheets" the employees use to keep track of progress. People move around quarterly, so I want to be able to update my Roster and then let the programming update the sharing status of their sheets instead of clicking on every sheet and copy-pasting emails.
As far as I know there is no current possible way to use google products to achieve this. Are there any other ways, barring a New Feature developed by Google?
I don't think I fully understand your requirements, so I'll start be rephrasing what I do understand.
For every employee, generate a list of who they're working with that quarter.
For a certain set of files owned by the employee, make those files editable to the employee's current co-workers.
For point 1, you already have the list built out in Google Sheets, so you can read the contents into arrays for processing. You can use Google Apps Script Spreadsheet Service for this. Example:
var roster = SpreadsheetApp.getActive(); //assuming the script is running within the Roster spreadsheet
var employeesSheet = roster.getSheetByName("Employees"); //assuming sheet name is "Employees"
var employeeEmails = employeesSheet.getRange("B2:B").getValues(); //assuming the emails are in column B with the first row as header
//In this next line I'm going to make a very big simplification.
//I will assume that the coworkers emails are listed as "coworker1#company.com;coworker2#company.com" in the cell.
//This is likely not the case, but you may already have this formatted in a way that works.
//If not, you can merge these values in Google Apps Script, but I'll consider that outside the scope of this question.
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
For point 2, I assume you already have a way of determining which files need to have their access permissions modified and that you have permission to make those modifications. You'll need to use the Drive Service for this part. In my example, I will assume that all relevant files are saved in a folder specific to each employee and that the folder ID is saved in column D.
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
//At this point, you could give direct access to the entire folder,
//or just to the files within the folder, as I will do.
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
Please note that in the above:
This is untested code and meant only to demonstrate how to achieve what I think you're looking for.
No access permissions are being revoked. This would be quite trivial to add, though.
The folder.getFiles() command only gets files that are children of the folder. So, if the folder has child folders, you'll need to traverse through those as well.
You may want to create a custom menu in your Roster spreadsheet to run this script
In the end, including the custom menu, your code could like:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Reset Permissions", functionName: "resetPermissions"});
ss.addMenu("Roster Actions", menuEntries);
}
function resetPermissions() {
var roster = SpreadsheetApp.getActive();
var employeesSheet = roster.getSheetByName("Employees");
var employeeEmails = employeesSheet.getRange("B2:B").getValues();
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
}
For reference, this is how I assumed the example "Employees" sheet in the "Roster" spreadsheet to look:
I’m very new to Google Apps Script, and I’m having trouble trying to accomplish my goal.
I have a Google Sheets Workbook that allows users to:
Select a name from a drop down (each name has a unique/individual
google workbook URL associated with it)
Type in a desired spreadsheet name
Press a “Push Sheet” button
Once the user presses the button, I’m trying to accomplish the following things:
Duplicate the sheet 'Template - Do Not Modify’ that already exists on target workbook (the URL associated with the selected name)
Rename the duplicated sheet to the desired spreadsheet name
Copy the range A7:D150 from the sheet “Tracker” on the original workbook to the range A7:D150 newly created sheet on the target workbook
The original sheet is set up to have the user authorize the workbook connection prior to running the script.
Here's my code:
function cloneGoogleSheet() {
var sheet = SpreadsheetApp.getActiveSheet();
var name = sheet.getRange("B10").getValue();
var url = sheet.getRange("f5").getValue();
var tss = SpreadsheetApp.openByUrl(url);
tss.setActiveSheet(tss.getSheetByName('Template - Do Not Modify'));
tss.duplicateActiveSheet();
var activesheet = tss.getActiveSheet();
activesheet.setName(name);
}
My issues are:
It doesn't seem like utilizing ActiveSheets is a safe way to do all of this and that there's a better way.
When attempting to use the URL variable (the script runs fine with a hardcoded URL value), I get an invalid argument: URL error. The cell F5 updates to a new URL based on what name is selected from the drop down, using a lookup which references names with unique URLs:
=lookup(B4,
{P71,P72,P73,P74,P75,P76,P77},
{Q71,Q72,Q73,Q74,Q75,Q76,Q77}
)
Given the fact that I'm using all these ActiveSheet variables, I'm not sure how to get back to my original sheet to copy the ranges.
I would very much appreciate someone showing me the correct way to do this. Thanks!
Have you tried using "getSheetByName"?
Try Armit Agarwal's tutorial on Duplicate a Sheet in Google Spreadsheets:
function cloneGoogleSheet() {
var name = "labnol";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Template').copyTo(ss);
/* Before cloning the sheet, delete any previous copy */
var old = ss.getSheetByName(name);
if (old) ss.deleteSheet(old); // or old.setName(new Name);
SpreadsheetApp.flush(); // Utilities.sleep(2000);
sheet.setName(company);
/* Make the new sheet active */
ss.setActiveSheet(sheet);
}
This is a question about a Google docs scripting document.
I would like to create a script that, when I run it, will transfer one row of data from a questionnaire (that I choose before running the script) to a completely new google docs word document.
Is this possible, and if so how would I do it?
Shouldn't be too difficult - tricky bit comes with what you want to do with the data in the new doc. Example script to do this would be:
function sendToNewSheet() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveRange().getRowIndex();
var range = sheet.getRange(row,1,1,sheet.getLastColumn()).getValues();
var doc = DocumentApp.create(new Date().getTime());
doc.appendParagraph(range.join());
doc.saveAndClose();
}
function onOpen() {
var subMenus = [{name:"Send to new sheet", functionName: "sendToNewSheet"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu("Help Desk Menu", subMenus);
}
With that, you can select a cell in your spreadsheet and then use the menu to execute a function that will take the data in that cell's row, create a new document, and add the data into that document. If you wanted to name the document based on the data, you could do:
var doc = DocumentApp.create(range[0][1]);
Which would use the data in the second column. The document is created in your top level directory but you can move it after it's created into a specific folder you want.