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
Related
What is causing the error
"Exception: Service Spreadsheets failed while accessing document with ID ..."
in my Google Apps Script code?
How can I fix this error and successfully import an Excel sheet (at the moment that sheet is located on Google drive, can I load it from my hard drive, when I run the script) into existing Google Sheet using Google Apps Script?
Is there a specific configuration or permission that needs to be set in order for the code to access and read an Excel file from Google Drive?
I am not very familiar with Google Apps Script and any advices are welcomed.
Here is my script
function importExcelSheet() {
// Ask which Excel file to load
var file = DriveApp.getFilesByName(Browser.inputBox("Enter the name of the Excel file to load:")).next();
// Read the Excel file
var spreadsheet = SpreadsheetApp.open(file);
// Get the first sheet from the Excel file
var sheet = spreadsheet.getSheets()[0];
// Import the sheet into the active Google Sheet
var currentSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var newSheet = currentSpreadsheet.insertSheet(sheet, 0);
// Set the name of the new sheet in the format "YYYY.MMM"
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth();
var monthName = Utilities.formatDate(date, "GMT", "MMM");
newSheet.setName(year + "." + monthName);
}
// Add the function to the Custom Google Sheet menu
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{name: "Import Excel Sheet", functionName: "importExcelSheet"}];
spreadsheet.addMenu("Custom Menu", menuEntries);
}
I added "Drive API" to the Apps Script from "Services" menu.
This should work (haven't tested it) but this is not perfect because creating a copy of your source file, in order to read it with SpreadsheetApp
And you need to activate Advanced Drive API : https://developers.google.com/apps-script/advanced/drive
// your code:
// Ask which Excel file to load
var file = DriveApp.getFilesByName(Browser.inputBox("Enter the name of the Excel file to load:")).next();
//then:
if (file.getContentType() == "application/vnd.ms-excel" || file.getContentType() == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
var id = Drive.Files.insert({title: "new", mimeType: MimeType.GOOGLE_SHEETS}, file.copyBlob()).id;
var ss = SpreadsheetApp.openById(id);
//back to your code
}
I have replicated the google file picker in a web app.
My question is how would I tell the google picker to make a copy of the file when uploading it to google drive ?
Any help would be much appreciated.
I realised that google picker could not do what I needed so Google App Script to the rescue.
Firstly you need to create a new google spreadsheet
Under "Tools->Script Editor" add the following code
Thought trial an error I came up with the following.
function copyFiles() {
var dApp = DriveApp; // Get the drive app
var folderIter = dApp.getFoldersByName('parentFolder'); //Get folder my id
var folder = folderIter.next(); // Get the first folder
var fileIter = folder.getFiles(); // File iterator
var storageFolder = folder.getFoldersByName('childFolder').next(); // Get target folder
var subFolderIter = storageFolder.getFiles(); // sub folder File iterator
while(fileIter.hasNext()) {
var file = fileIter.next(); // Get the current File
var fileName = file.getName();
// Check if the current file exists in a coped folder
// If false make a copy else do noting
// This check prevents duplicate, Becasue makeCopy generates uniques ID everytime
if(!storageFolder.getFilesByName(fileName).hasNext()) {
//Logger.log('Files does NOT exists');
file.makeCopy(storageFolder);
} else {
//Logger.log('Files does exists');
}
}
}
Hope this helps anyone who might need.
Note: You will need to set up triggers for the script to run when required
Is there a way to make a google spreadsheet script run if the sheet is edited by IFTTT instead of by a person via the sheets browser?
Background: IFTTT put a value in a specific cell. My google spreadsheet script says if the cell is not empty; insert a new row. So my script is running if my sheet is edited by me manually and I put a value in that cell. However, if IFTTT adds a new entry to the spreadsheet nothing happens. I have tried both the onEdit and onChange triggers to no avail. Any suggestions?
The actual script I am using is below:
(function InsertRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Diagramm');
var values = sheet.getRange('B2').getValues();
if (values[0][0] != "")
sheet.insertRowBefore(2);
})();
So I followed the tutorial on Google Driver API Push Notifications and added following code to my script:
function listFiles() {
var optionalArgs = {
maxResults: 10
};
var response = Drive.Files.list(optionalArgs);
var files = response.items;
if (files && files.length > 0) {
Logger.log('Files:');
for (i = 0; i < files.length; i++) {
var file = files[i];
Logger.log('%s (%s)', file.title, file.id);
}
} else {
Logger.log('No files found.');
}
};
But what do I need to do now? Sorry I am not a good programmer...
You have to use Drive API push notifications to pick up these changes.
This example on using Apps Script with the Drive API is helpful to get started.
Spencer Easton has also provided a tutorial on get GMail push notifications that'll give you some hints on setting this up as you have to make some changes in the dev console.
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
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.