I am trying to boost my Google knowledge by getting into scripting, and I have researched high and low for a solution to my situation to no avail.
I have a Google Sheet that is serving as a template. When the original file is opened, I want to launch a dialog to enter a student ID#. This number will pass into a specified cell in the template, which results in some auto-populated cells in the sheet (using spreadsheet functions). Once the cells have been populated, I want to make a copy of the file with a specific naming structure and store it in a specified folder in Google Drive. Lastly, I want that new file to open in a new window for further editing.
So far, I can get the dialog box to pop up for the ID#, I can pass that number to the sheet, and I can make a copy of the template and rename it accordingly.
What I CANNOT do is get the new file to open automatically in a new tab. I also need the new file to not run the "onOpen" script.
Here is what I have so far for each of these endeavors.
The code below creates a dialog box to enter a Student ID and passes it to the sheet to a specified cell:
function BuildUI() {
var app = UiApp.createApplication();
app.setTitle('Make a Copy - Please enter the Student ID# below:');
var panel = app.createVerticalPanel();
var textBox = app.createTextBox();
textBox.setName('stuId').setId('StudentID');
var button = app.createButton('Submit');
panel.add(textBox);
panel.add(button);
var clickHandler = app.createServerClickHandler('responses');
button.addClickHandler(clickHandler);
clickHandler.addCallbackElement(panel);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function responses(e){
var app = UiApp.getActiveApplication();
var textBoxValue = e.parameter.stuId;
var sheet = SpreadsheetApp.getActiveSheet();
var studentID = sheet.getRange('Y4').setValue(textBoxValue);
var dateToday = sheet.getRange('C5').setValue(new Date());
return app.close();
}
The above code works for what I need it to do. I only include it for reference (and suggestions for cleaning it up ;)
This next code block makes a copy of the file with the new values, renames it, and saves it to a designated folder in Google Drive. Again..this works for me, but I include it for reference and suggestions:
function makeCopy(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var firstName = sheet.getRange('O4').getDisplayValue();
var lastName = sheet.getRange('E4').getDisplayValue();
var date = sheet.getRange('C5').getDisplayValue();
var stuId = sheet.getRange('Y4');
var grade = sheet.getRange('AH4').getDisplayValue();
var fileName = (lastName+ ", " +firstName+ " - " +stuId+ " - Grade " +grade+ " - " +date);
var destFolder = DriveApp.getFolderById('folderID');
destFolder.setSharing(DriveApp.Access.DOMAIN_WITH_LINK, DriveApp.Permission.VIEW);
DriveApp.getFileById(sheet.getId()).makeCopy(fileName, destFolder);
}
Lastly, my onOpen function strings this all together (plus one other function) to run as soon as the template is opened:
function onOpen(){
clearCells(); //Clear all content left behind by last editor
BuildUI();
makeCopy();
}
Any help in getting this workflow dialed in is greatly appreciated (most of this I have accomplished already, I just include it for you understanding of my overall needs):
User Interface Dialog Box to capture Student ID (done, but could use suggestions for cleaning up)
Pass ID to cell Y4 and current date to cell C5 (done...just included for understanding of overall need)
Make a copy of the original file and rename it to "Last Name, First Name - StuID - Grade - Date and store in specified Folder in Google Drive (done...just included for understanding of overall need)
NEED -- Open newly created file in a new tab in the browser without running the attached scripts (ideally, the scripts will not be included in the copy if possible)
Bonus points for any help in recreating the UI using the HtmlService in Google scripts since the UI Service is deprecated and functionality may go away the moment I figure all this out.
Thanks in advance for any help on this tall order.
You could capture the google file object in the makeCopy() with
gFile = DriveApp.getFileById(sheet.getId()).makeCopy(fileName, destFolder);
return gFile;
then add this function to open a new sheet:
function openNewSheet(gFile) {
var spreadsheetId = gFile.getId();
var url = "https://docs.google.com/spreadsheets/d/"+spreadsheetId;
//SpreadsheetApp.getUi().alert('url is ' + url);
var html = "<script>window.open('" + url + "');google.script.host.close();</script>";
var userInterface = HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModalDialog(userInterface, "Open Sheet");
}
Finally you can add openNewSheet() to the end of onOpen()
Some credit goes to this video: https://www.youtube.com/watch?v=2y7Y5hwmPc4
Related
I am trying to upload pdf file to a single cell in google sheet just like we insert image in a google sheet cell. I've searched for quite some time now, but haven't been able to find any solutions to this. I have tried the following code:
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var menuEntries = [];
menuEntries.push({name: "File...", functionName: "doGet"});
ss.addMenu("Attach ...", menuEntries);
}
function doGet(e) {
var app = UiApp.createApplication().setTitle("upload attachment into Google Drive");
SpreadsheetApp.getActiveSpreadsheet().show(app);
var form = app.createFormPanel().setId('frm').setEncoding('multipart/form-data');
var formContent = app.createVerticalPanel();
form.add(formContent);
formContent.add(app.createFileUpload().setName('thefile'));
formContent.add(app.createHidden("activeCell", SpreadsheetApp.getActiveRange().getA1Notation()));
formContent.add(app.createHidden("activeSheet", SpreadsheetApp.getActiveSheet().getName()));
formContent.add(app.createHidden("activeSpreadsheet", SpreadsheetApp.getActiveSpreadsheet().getId()));
formContent.add(app.createSubmitButton('Submit'));
app.add(form);
SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
function doPost(e) {
var app = UiApp.getActiveApplication();
app.createLabel('saving...');
var fileBlob = e.parameter.thefile;
var doc = DriveApp.getFolderById('0B0uw1JCogWHuc29FWFJMWmc3Z1k').createFile(fileBlob);
var label = app.createLabel('file uploaded successfully');
var value = 'hyperlink("' + doc.getUrl() + '";"' + doc.getName() + '")'
var activeSpreadsheet = e.parameter.activeSpreadsheet;
var activeSheet = e.parameter.activeSheet;
var activeCell = e.parameter.activeCell;
var label = app.createLabel('file uploaded successfully');
app.add(label);
SpreadsheetApp.openById(activeSpreadsheet).getSheetByName(activeSheet).getRange(activeCell).setFormula(value);
app.close();
return app;
}
Since UiApp has been deprecated so it shows the error "UiApp has been deprecated. Please use HtmlService instead". I have tried the following line to avoid UiApp error but of no use:
var app = HtmlService.createHtmlOutput();
Is there any workaround that we can get to avoid this error? Thank you.
I believe your goal is as follows.
From your following comments,
I have pdf file in local pc, I would have a google sheet add-on with an option "file upload". I would click on that, it will upload file in the Drive folder which we have specified in script and the active google sheet cell will show the confirmation message.
I want to put the message in currently active cell of the sheet
You wanted to upload a PDF file on the local PC to Google Drive. And you want to put the confirmation message to a current active cell. You want to achieve this by a sidebar using HTML and Google Apps Script.
In this case, how about the following sample script?
Sample script:
Google Apps Script side: Code.gs
Please copy and paste the following script to the script editor of Google Spreadsheet as the script file and save the script.
const openSidebar = _ => SpreadsheetApp.getUi().showSidebar(HtmlService.createHtmlOutputFromFile("index"));
function upload(e){
const message = "sample confirmation message"; // Please set your confirmation message.
DriveApp.createFile(Utilities.newBlob(...e));
SpreadsheetApp.getActiveRange().setValue(message);
}
HTML&Javascript side: index.html
Please copy and paste the following script to the script editor of Google Spreadsheet as the HTML file and save the script.
<form>
<input type="file" name="file" onchange="upload(this.parentNode)" accept=".pdf,application/pdf" />
</form>
<script>
function upload(e){
const file = e.file.files[0];
const fr = new FileReader();
fr.onload = e => google.script.run.upload([[...new Int8Array(e.target.result)], file.type, file.name]);
fr.readAsArrayBuffer(file);
}
</script>
Testing:
When you run the function openSidebar, the sidebar is opened. And when you select the file from the input tag, the file is uploaded to the root folder of Google Drive, and the confirmation message is put to the active cell.
Note:
In this method, the maximum file size is 50 MB because of the specification of the Google Apps Script side. Please be careful about this.
This is a simple sample script for achieving the goal of your question. So please modify this for your actual situation.
Reference:
Dialogs and Sidebars in Google Workspace Documents
I created a script to create a new folder every time a form is submitted. The point of the script was to put each newly created folder in a specific parent folder determined by a column value on a spreadsheet (new values are generated when forms are submitted). At the moment the script does not fire automatically even though a trigger event is setup, but will fire and create the new folder in the proper location when manually run. Any help would be appreciated.
function createNewFolder() {
// identify the sheet where the data resides
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("Form Responses 1");
var ids = ss.getSheetByName("Form Responses 1");
//identify the cell that will be used to name the folder
var getName = names.getRange(names.getLastRow(), 3).getValue();
//identify the cell that determines which parent folder to use
var folderId = ids.getRange(ids.getLastRow(), 5).getValue();
//identify the parent folder the new folder will be in
var parentFolder = DriveApp.getFolderById(folderId);
//create the new folder
var newFolder = parentFolder.createFolder(getName);
}
The trigger fails about 85% of the time and is setup to fire when a new form response is logged on the associated spreadsheet.
Try replacing your onFormSubmit function with this:
This function should be created in the spreadsheet that has the linked sheets. This function utilizes the data that is sent in the form submit event object. Don't forget to include the 'e' in the function as a parameter.
function createNewFolder(e) {
var parentFolder = DriveApp.getFolderById(e.values[4]);
var newFolder = parentFolder.createFolder(e.values[2]);
}
Event Object Form Submit
Also you may want to look at this question since we have been seeing a lot of problems with spurious form submit triggers. If you don't need to implement it fine but it might be something to consider.
It's most likely an async issue. The parentFolder.createFolder function probably is getting called before the parentFolder is done fetching data from DriveApp.
Try this:
var newFolder = parentFolder.then(() => {
parentFolder.createFolder(getName)
})
I am trying to figure out how to remove someone from a spreadsheet using google app scripts.
Essentially, I have a central spreadsheet with information such as emails, names, UID's etc on it. I am trying to pull the email from this spreadsheet and use the removeEditor function to remove that email from another spreadsheet. You can view the code below.
var officerIDrow = officerID + 1;
var Tracker = SpreadsheetApp.getActive().getSheetByName('P_Tracker'); //the button is on the same sheet as this, this is why it is get active.
var PTBooking = SpreadsheetApp.openById("1JPS69ko99dQTEwjplF_l2l2G_T8RyHjxCyMxXd_AV_s"); //Referring to the other sheet where the email will be removed from editors.
var EmailAddressRange = "F" + officerIDrow; //This is the column where the emails are stored. The officer ID row refers to the user inputted value in a dialog. Don't worry about this, I have already checked to see if this is the issue,
var EmailAddress1 = Tracker.getRange(EmailAddressRange);
var EmailAddress2 = EmailAddress1.getValue();
var EmailAddress3 = Utilities.formatString(EmailAddress2); //In my desperation, I was trying to see if setting it as string would help.
PTBooking.removeEditor(EmailAddress3);
This isn't the full version of the code. If you'd like to see it, you can click here. But all that matters is above, everything else works fine.
The code above runs fine until it hits the last line where it tries to remove the email. The error message that appears says: "Invalid email: ". I'm assuming after the "email:" bit, it should display what has been pulled. But it doesn't! I have no idea why it isn't finding and using the email to remove people.
Can anyone spot any issues?
Thanks,
Shaun.
This basic test worked for me. It could read email address from the spreadsheet then remove editors from the external sheet. I tried to copy your example, but I don't know how the officerIDrow works, but I assume it's a number. So just stored a number as a var
function myTest() {
var ss = SpreadsheetApp.openById("ID HERE");
var idRow = 11;
var tracker = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("tracker");
var emailCell = "F"+idRow;
Logger.log(emailCell);
var emailAddress = tracker.getRange(emailCell).getValue();
Logger.log(emailAddress);
ss.removeEditor(emailAddress);
var editors = ss.getEditors();
Logger.log(editors);
}
I've left the Logger bits in as it will help point you at what script is doing at each point.
The email address in the cell must be plain, such as google#google.com
I have a Google Sheets file with an attached Script. The script does a number of things, one is it makes a clone of it self using makeCopy. This portion works. Now I want to be able to keep the same cloned Google file name and same Google file ID and just update the content which includes a Spreadsheet and the associated Google script.
if (!fileFound){
var file = masterSSFile.makeCopy(reportFileName, RepFolder);
} else {
oldFile.setContent(masterSSFile.getBlob());
}
When I use makeCopy with the same file name it creates a second file with the same name but with a different file ID.
The else portion fails because .setContent argument seems to just accept text. The result is the word "Blob" in the oldFile, everything else is gone.
I have other scripts that update the contents of a existing spreadsheet by overriding the contents of the various sheets, but I also want the associated script to also be included in the updated file keeping the same file ID.
I found this....
Overwrite an Image File with Google Apps Script
and tried using
var masterSpreadsheetID = SpreadsheetApp.getActiveSpreadsheet().getId();
var masterSpreadsheetFile = DriveApp.getFileById(masterSpreadsheetID);
var oldFileID = oldFile.getId();
var oldFileName = oldFile.getName();
var newBlob = masterSpreadsheetFile.getBlob();
var file = {
title: oldFileName,
mimeType: 'application/vnd.google-apps.spreadsheet'
};
var f = Drive.Files.update(file, oldFileID, newBlob);
I get error: "We're sorry, a server error occurred. Please wait a bit and try again. " on this line: "Drive.Files.update(file, oldFileID, newBlob);"
After reading this:
https://github.com/google/google-api-nodejs-client/issues/495
it looks like Drive.Files.update(), does not support bound scripts.
I have a workflow process that runs in weird combination of html and excel, this was already done when I came to work here so I'm no able to restart the process, well here is the deal:
After a certain step on the flow, a html file is sent through email, this file contains an active x that will automatically open excel with some given parameters, however even though everything seems to build with parameters the path for excel is hardcoded, we never had an issue with this as everyone was using Excel 2003 and pretty much everyone had the same image so the path was the same, but now some users (top management) will be migrating to office 2010. Therefore I need a way to automatically detect the excel version through the active x so the html file will open the correct excel version.
Any ideas?
Thanks!
EDIT
this is what I use:
<script language="JavaScript">
function LoadVendor()
{
var vendor = document.getElementById("vendor").value;
document.getElementById("vend").innerHTML=vendor;
var BIDnum = document.getElementById("BIDnumber").value;
document.getElementById("BIDnum").innerHTML=BIDnum;
}
function openExcelDocPath()
{
var shell = new ActiveXObject("WScript.Shell");
var excelexe = document.getElementById("excelexe").value;
var excelprg = document.getElementById("excelprg").value;
var vendor = document.getElementById("vendor").value;
document.getElementById("vend").innerHTML=vendor;
shell.run( "\"" + excelexe + "\"" + excelprg , 1, false );
try{objExcel.comaddins("SAS.OIBootStrap.Connect").connect = "False"; }
catch(err)
{ }
}
</script>
I'm not 100% on what your after but you could drop the physical path entirely;
var Excel = new ActiveXObject("excel.application");
Excel.Visible = true;
Excel.Workbooks.Add(); //to keep resident if you want interactivity
//can open something here ...
//or just get the path/version
alert( Excel.version );
alert( Excel.path );
//to kill
//Excel.Quit();
//Excel = null;