I would like to open each file in a folder via script. Below is what I have tried. This is my first shot at any script in sheets.
This code runs but does not open file, I could be a mile off on this but I can't figure out how to make it open the files. Thanks for your help
function myFunction() {
var dApp = DriveApp;
var folder = dApp.getFoldersByName("test").next();
var filesIter = folder.getFiles();
while(filesIter.hasNext()) {
var files = filesIter.next();
var ss = SpreadsheetApp.open(files);
}
}
I simply want it to open all the files in a folder in this case "test". there are currently two google sheets in the folder.
Google Apps Script server-side code can't do actions on the client side like opening a spreadsheet on the user web browser but you could use HTML Service to use client side code to achieve your goal.
Related
Open a URL in a new tab (and not a new window) using JavaScript
Open URL in same window and in same tab
You can read open files from Scripts but not in the way that users can open files. You can open them on the server and read and/or write data but the file doesn't open up in edit mode like it does when you open it as a user.
Here's a script that opens up spreadsheets and reads their name and id and returns it to a webapp.
HTML:
<html>
<head><title></title>
</head>
<body>
<div id="data"></div>
<script>
window.onload=function(){
google.script.run
.withSuccessHandler(function(ssA){
var html='';
for(var i=0;i<ssA.length;i++) {
html+='<br />' + 'Name: ' + ssA[i].name + ' Id: ' + ssA[i].id;
}
document.getElementById('data').innerHTML=html;
})
.readSpreadsheetsInAFolder();
}
</script>
</body>
</html>
CODE.gs:
function readSpreadsheetsInAFolder() {
var ssA=[];
var folders=DriveApp.getFoldersByName("LinkedSpreadsheets");
while(folders.hasNext()){
var folder=folders.next();
var files=folder.getFilesByType(MimeType.GOOGLE_SHEETS);
while(files.hasNext()) {
var file=files.next();
var ss=SpreadsheetApp.openById(file.getId());
ssA.push({name:file.getName(),id:file.getId()});
}
}
return ssA;
}
This function was written for my account so you may have to modify the Folder Name to get it to work on your account.
Related
I'm trying to use google script to display a bunch of data in a HTML file, however, my data doesn't seem to make it to the HTML file and I have no idea why. Can someone please tell me what I'm missing here?
Path: htmlList.html
<!DOCTYPE html>
<html>
<head>
<base target="_top" />
</head>
<body>
My HTML page
<? for(var i = 0; i <= (users.length -1); i++) { ?>
<p><?= users[i].firstName ?></p>
<? } ?>
</body>
</html>
Path: Code.js
function doGet(users) {
var html = HtmlService.createTemplateFromFile("htmlList");
html.users = users;
return html.evaluate().setTitle("Test my app");
}
function generateLinks() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var rr = spreadSheet.getLastRow();
var users = [];
for (var i = 3; i <= rr; i++) {
var firstName = spreadSheet.getRange(i, 1).getValue();
var user = {
firstName: firstName
};
users.push(user);
}
doGet(users);
}
You want to open new tab for own browser using the created HTML data, when you run the function at the script editor.
You are using the container-bound script.
If my understanding is correct, how about this modification?
Modification points:
In this modification, I used the following flow. Please think of this as just one of several answers.
By running runScript(), a dialog is opened.
The opened dialog runs a Javascript for opening new tab of the browser and open the URL of Web Apps.
At this time, generateLinks() is run from doGet(), and the values are retrieved and put to HTML data.
Close the dialog.
By this flow, when you run the function at the script editor, the created HTML is opened as new tab of your browser.
Modified script:
Please copy and paste the following script to the container-bound script of Spreadsheet. And then, please redeploy Web Apps as new version. At that time, as a test case, please set Execute the app as: and Who has access to the app: as Me and Anyone, even anonymous, respectively. In this case, you are not required to modify the script of HTML side.
function doGet() {
var html = HtmlService.createTemplateFromFile("htmlList");
html.users = generateLinks(); // Modified
return html.evaluate().setTitle("Test my app");
}
function generateLinks() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var rr = spreadSheet.getLastRow();
var users = [];
for (var i = 3; i <= rr; i++) {
var firstName = spreadSheet.getRange(i, 1).getValue();
var user = {
firstName: firstName
};
users.push(user);
}
return users; // Modified
}
// I added the following function. Please run this function.
function runScript() {
var url = ScriptApp.getService().getUrl();
var script = "<script>window.open('" + url + "', '_blank').focus();google.script.host.close();</script>";
var html = HtmlService.createHtmlOutput(script);
SpreadsheetApp.getUi().showModalDialog(html, 'sample');
}
When var spreadSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); is used, the 1st sheet of Spreadsheet is used. So when you want to retrieve the values from the specific sheet, for example, please modify to SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheetName").
Note:
If you modified the script of Web Apps, please redeploy Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.
References:
HTML Service: Create and Serve HTML
HTML Service: Templated HTML
Taking advantage of Web Apps with Google Apps Script
Assuming that your data on the spreadsheet looks something like this -
And the desired output looks something like this (you're free to modify the CSS in your .html file) -
You can achieve this by using the following code -
For Code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getUsers() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var users = ss.getRange(1, 1, ss.getLastRow(), 1).getValues();
return users;
}
For Index.html file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess1(users) {
var div = document.getElementById('userFirstNames');
div.innerHTML = users;
}
google.script.run.withSuccessHandler(onSuccess1).getUsers();
</script>
</head>
<body>
<div id='userFirstNames'></div>
</body>
</html>
Hope this helps.
I have a sheet on my Google Drive called "Titito." I use SpreadsheetApp.open(Titito) to open it but it returns:
ReferenceError: "Titito" is not defined. (ligne 5, fichier "macros"
When I try to open it by its URL:
SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1NTql7GMdPg8at0VEaz2jFmzOd4zBVjwArqDqWBww_Ww/edit#gid=0');
it returns:
You do not have permission to call SpreadsheetApp.openByUrl. Required permissions:
While it's my file, created by me.
How can I open a sheet in my drive by a script in an other sheet?
I just would like to know how to do as I did it on Visual Excel (Workbooks.Open Filename:="c:\TermFB\Charges\chargecpt.xls") but on google script
Thanks.
If "Titito" is the name of the actual file, then SpreadsheetApp.open(Titito) is not the way; sa you can see in the documentation, that uses file objects. In order to get it through the name, you will need to instead use DriveApp (Documentation here). With it you can get the files in your Drive and get the one you're looking for, the code for that looks like this:
function fn(){
var files = DriveApp.getFiles();
var file;
while (files.hasNext()){
file = files.next();
if (file.getName() == "Titito")
break;
}
var ss = SpreadsheetApp.open(file).getUrl();
// rest of your code...
}
UPDATE
OP needed a way to open the actual Spreadsheet through the script, after following the instructions in this video, they were able to achieve what they wanted.
function myFunction() {
// CREATE AND OPEN A FILE CALLED Toto
var ssNew = SpreadsheetApp.create('Toto');
var tyty = ssNew.getUrl();
// var selection=SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
var html = "window.open('" + tyty + "');google.script.host.close();";
var userInterface = HtmlService.createHtmlOutput(html)
SpreadsheetApp.getUi().showModalDialog(userInterface, 'Open Tab');
}
Thanks to AMolina very helpful for my first step on google script !
I'm trying to write a Google Apps Script to download all files in a particular Drive folder (likely .csv files). I have found the getDownloadUrl() method but I haven't been able to figure out what to do with it. I'm currently trying the following code, where files is the list of the files in the folder:
while(files.hasNext()) {
var response = UrlFetchApp.fetch(files.next().getDownloadUrl());
Logger.log(response.getContentText());
}
When I try to run the code, however, I get a 401 error which I guess means I lack the proper authorization? But I was under the impression that I wouldn't need to go through all of the OAuth2 steps if everything was taking place within my one Google account. The Google guide to connecting to external APIs makes it look like I should be able to just fetch the url. I've already gotten access to my Drive files, because the download URL does exist when I run that method. What am I missing here? I'm really new to all of this so maybe it's something basic.
Thanks!
EDIT:
I managed to fix the 401 error by modifying the code as follows:
while(files.hasNext()) {
var response = UrlFetchApp.fetch(files.next().getDownloadUrl(),{headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
Logger.log(response.getContentText());
}
But the issue remains that this only returns the contents to me, rather than downloading the file. How can I initiate a download from the results of this fetch call?
Besides listing all download links, I guess original poster also wants to download files to user's computer (according to earlier discussion).
To do this, encode blob with base 64 in server side (e.g. Google App Script) and download with data URI in client's browser. Below are code for this, with help of this answer.
Google App Script
...
function getBlobInBase64(fileId){
// omit authorization code if any
var file = DriveApp.getFileById(fileId);
var blob = file .getBlob();
return {
file_name: file.getName(),
mime: file.getMimeType(),
b64: Utilities.base64Encode(blob.getBytes());
}
...
Javascript that serve with index.html
...
function getFile(fileId){
google.script.run.withSuccessHandler((data) => {
var uri = 'data:' + data.mime + ';charset=ISO-8859-1;base64,' + encodeURIComponent(data.b64);
downloadURI(uri, data.file_name);
}).withFailureHandler((err) => {
console.log(err);
}).getBlobInBase64();
}
...
NOTE: I haven't run this code but the method should work as used in my other project.
This will log the file names & URLS for any files available for downloading (first 100 in root drive):
function myFunction() {
var files = DriveApp.getFiles();
var c = 0;
while (files.hasNext() && c<100) {
var file = files.next();
Logger.log("File Name: " + file.getName());
Logger.log(" Download URL: " + file.getDownloadUrl());
c++;
}
}
My answer might be a bit off but I think you have a better chance downloading files from Google Drive using the webContentLink as it is the method I commonly use. I obtain webContentLink by using Files.list and ask for webContentLink in the fields parameter. I run that link through the browser and it downloads the file.
If you are trying to download Google Drive files to local computer using Google Apps Script, Then please understand that Google Apps Script is a server side scripting language. It can't download and save files to your local drive.
Here is a webapp that may be helpful for you. It does not do exactly what you are looking for but you may be able to edit it and get a result. Hope it helps!
CODE:
function doGet(e) { // main function
var template = HtmlService.createTemplateFromFile('index.html'); // filename always!
return template.evaluate().setTitle('Search Drive').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
// Process the form
function processForm(searchTerm) {
var resultToReturn;
Logger.log('processForm was called! ' + searchTerm);
resultToReturn = SearchFiles(searchTerm); // Call to the search files function to search files on google drive
Logger.log('resultToReturn: ' + resultToReturn);
return resultToReturn; // return the results
}
function SearchFiles(searchTerm) {
var searchFor ="title contains '" + searchTerm + "'"; //single quotes are needed around searchterm
var owneris ="and 'YOUREmail#email.com' in Owners"; //email address to search for
var names = [];
Logger.log(searchFor + " " + owneris);
var files = DriveApp.searchFiles(searchFor + " " + owneris);
while (files.hasNext()) {
var file = files.next();
var fileId = file.getId();// To get FileId of the file
var lm = file.getLastUpdated();
var name = file.getName()+"|~|"+fileId+"|~|"+lm; // Im concatenating the filename with file id separated by |~|
names.push(name); // adding to the array
}
return names; // return results
}
INDEX.html
<html>
<head>
<base target="_top">
<script>
function displayMessage() {
var searchTerm;
searchTerm = document.getElementById('idSrchTerm').value;
console.log('searchTerm: ' + searchTerm );
// Below call means: call to processForm passing the searchTerm value (previously escaped) and after finish call the handleResults function
google.script.run.withSuccessHandler(handleResults).processForm(searchTerm.replace("'","\'"));
}
function handleResults(results){
console.log('Handle Results was called! ');
document.writeln('BACK<br/><br/>');
var length=results.length; // total elements of results
for(var i=0;i<length;i++)
{
var item=results[i];
item=item.split("|~|"); // split the line |~|, position 0 has the filename and 1 the file id
document.writeln("<b><a href='https://docs.google.com/document/d/"+item[1]+"' target='_blank'>"+item[0]+"</b></a> (Last modified: "+item[2]+")<br/><br/>"); // write result
}
document.writeln("End of results...");
}
</script>
</head>
<body><center><br/>
Search: <input type="text" id="idSrchTerm" name="search">
<input type="button" value="search files on Google Drive" name="submitButton" onclick="displayMessage()"/>
</center>
</body>
</html>
I want to http post an image from html form to google apps script web app, and then add that image to google drive.
my apps script is below.
function doPost(e){
var date = new Date();
var timestamp = date.toString()
var adress = e.parameter.adress;
var cost = e.parameter.cost;
var item = e.parameter.item;
var check = e.parameter.image;
//add file to drive
var destination_id = "some ID"
var destination = DriveApp.getFolderById(destination_id);
destination.createFile(check);
};
when I execute, it returns a error ; cannot find method: createFile(String)
I think this is because "check" is a string, and I want to convert the submitted image to Blob.
How can I do this?
How about following sample? Added "getAs()". https://developers.google.com/apps-script/reference/drive/file#getAs(String)
These are very simple html and gas script I used for this test.
HTML: This file name is "form.html".
<form>
<input type="file" name="imageFile">
<input type="button" value="ok" onclick="google.script.run.upload(this.parentNode)">
</form>
GAS script:
function doGet() {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function upload(e) {
var destination_id = "some ID";
var img = e.imageFile;
var contentType = "image/jpeg";
var destination = DriveApp.getFolderById(destination_id);
var img = img.getAs(contentType);
destination.createFile(img);
}
For this sample script, if you want to save as a jpeg file, please change 'contentType' from 'image/png' to 'image/jpeg'. When you upload png file for contentType of 'image/jpeg', the png file is converted to jpeg file by 'getAs()'.
Updated: March 19, 2020
When V8 is enabled, it seems that this.parentNode cannot be sent to Google Apps Script side. I'm not sure whether this is a bug or the specification. I think that this might be resolved in the future update. But as the current workaround, I would like to add one more sample script for uploading the file using Web Apps, dialog and sidebar.
In this case, the file is sent to Google Apps Script side as the byte array. And the file is created from the byte array at Google Apps Script side.
HTML & Javascript: index.html
<input id="file" type="file" onchange="saveFile(this)" />
<script>
function saveFile(f) {
const file = f.files[0];
const fr = new FileReader();
fr.onload = function(e) {
const obj = {
filename: file.name,
mimeType: file.type,
bytes: [...new Int8Array(e.target.result)]
};
google.script.run.withSuccessHandler(e => console.log(e)).saveFile(obj);
};
fr.readAsArrayBuffer(file);
}
</script>
Google Apps Script: Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index.html');
}
function saveFile(e) {
var blob = Utilities.newBlob(e.bytes, e.mimeType, e.filename);
DriveApp.createFile(blob);
return "Done.";
}
Updated: December 9, 2021
After V8 runtime was released, there was a bug that when the file is sent from HTML form to Google Apps Script side using google.script.run, the file blob was the invalid data.
From Apps Script Pulse by Martin Hawksey, it was found that the invalid blob of sending the file of HTML form to Google Apps Script side using google.script.run has finally been resolved. In this case, this script can be used with V8 runtime.
HTML & Javascript side: index.html
<form>
<input type="file" name="file" onchange="google.script.run.withSuccessHandler(console.log).upload(this.parentNode)">
</form>
Google Apps Script side: Code.gs
const doGet = _ => HtmlService.createHtmlOutputFromFile('index.html');
const upload = ({file}) => DriveApp.createFile(file).getId();
IMPORTANT:
As an important point, in the current stage, when the above HTML is accessed as Web Apps (doGet), this script works. But when the above HTML is accessed as a dialog and a sidebar, file at the Google Apps Script side is undefined. By this, it seems that in the current stage, this HTML can be used with only Web Apps. Please be careful about this. I would like to believe that this situation is resolved in the future update.
I have a spreadsheet that keeps track of a series of documents. Inside the spreadsheet I have a button which, upon being pressed, locates a particular template file from my drive and makes a copy of it. That script looks like this:
function myFunction() {
var file = DriveApp.getFileById("<template doc id goes here>");
var folder = DriveApp.getFolderById("<folder where new file will go>");
var newfile = "<newly created file name goes here>";
file.makeCopy(newfile, folder);
}
Is there a way I can force the newly created document to open in a new tab once it is created? This way once the new doc is created, I do not need to navigate back to the folder and open in manually for editing.
If you are using HTML Service for the original button, you can simply add a window.open function.
<script>
function openTheUrl() {
window.open("http://www.stackoverflow.com");
};
</script>
The URL to the new document can be returned with the getUrl() method of the File Class:
Google Documentation - getUrl()
There are multiple steps to this process.
Call Apps Script gs function with google.script.run in HTML
Google server side code creates the new document and returns a value
The onSuccess callback function opens the new document
HTML Script tag to call apps script code, and define the success function:
<script>
window.callServerCode = function() {
google.script.run
.withSuccessHandler(openTheUrl)
.myFunction();
}
function openTheUrl(argNewUrl) {
Logger.log('argNewUrl: ' + argNewUrl);
window.open(argNewUrl);
};
</script>
The Apps Script code needs to return a value:
function myFunction() {
var file = DriveApp.getFileById("<template doc id goes here>");
var folder = DriveApp.getFolderById("<folder where new file will go>");
var newfile = "<newly created file name goes here>";
var newFile = file.makeCopy(newfile, folder);
var newDocURL = newFile.getUrl();
return newDocURL;
}
The google.script.run withSuccessHandler function automatically receives the return value.
As mentioned in this question How to open a URL link from JavaScript inside a Google Apps Script HTML Google Site Gadget calling window.open won't work because of caja sanitization.
however you can add the url to a cel, or create a link in the HTML. The user will have to click on it to open the new sheet which may be not the solution you wanted, but it would save the time to look into drive for that new file.