With Apps Script, it's not allowed to use iframes or AJAX calls. So, I was hoping to restructure my script. Basically, it's just supposed to be a single file chooser.
function doGet(e)
{
return HtmlService.createHtmlOutputFromFile('index');
}
function browse(e)
{
var use_root_folder = typeof(e.parameter.folder_id) == "undefined";
var base_folder;
if(use_root_folder)
{
base_folder = DriveApp.getRootFolder();
}
else
{
base_folder = DriveApp.getFolderById(e.parameter.folder_id);
}
//more code...
}
In sample code on apps script, it looks like I'm supposed to create an html file and put this in it...
<script>
google.script.run.browse();
</script>
Except the "e" argument is only available from within the actual script and not the html file? How would I go about passing a query string parameter from within the HTML file back to the script?
When using google.script.run, you pass variables directly. So you can simply call browser() with the ID of the folder you want.
In the script file:
function browse(folderID)
{
var use_root_folder = typeof(folderID) == "undefined";
var base_folder;
if(use_root_folder)
{
base_folder = DriveApp.getRootFolder();
}
else
{
base_folder = DriveApp.getFolderById(folderID);
}
//more code...
}
And in the HTML file:
<script>
google.script.run.browse(selectedFolderId);
</script>
Related
As the title suggest I have an Apps script where I need the Date created of the google doc but when i use the following code
''' var file = DriveApp.getFilesByName("filename")
var final = file.getDateCreated()'''
I get told that getDateCreated isnt a function and the same issue happens with getlastUpdated can anyone point out what im missing. Many thanks.
DriveApp.getFilesByName("filename") returns a FileIterator not a File. You need to iterate through the files, even if there is only one file with that name.
function test() {
try {
var files = DriveApp.getFilesByName("filename");
while( files.hasNext() ) {
var file = files.next();
console.log(file.getDateCreated());
}
}
catch(err) {
console.log(err);
}
}
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 project set up like this:
TestProject
-- Code.gs
-- 14885.gs
-- 23546.gs
I want to create a variable and set its value in "Code.gs" file. Then I should be able to access it in 14885.gs and 23456.gs files.
In Code.gs file, I used the PropertiesServices and created a variable that I wanted to access across other "gs" files under the project.
In Code.gs file
function onEdit(e){
totalHoursLoggedForStory_today = Number(e.range.getSheet().getRange("H3").getValue()) + Number(e.range.getSheet().getRange("H4").getValue()) + Number(e.range.getSheet().getRange("H5").getValue());
var userProperties = PropertiesService.getUserProperties();
var newProperties = {'hoursLogged': totalHoursLoggedForStory_today };
userProperties.setProperties(newProperties);
onEditOfH3(e);
}
In 23546.gs file
function onEditOfH3(e){
if (e.range.getA1Notation() == "H3")
{
var temp= userProperties.getProperty('hoursLogged');
sh.alert(temp);
}
Expected: In the 23546.gs file, I should be able to alert the property that I set in "Code.gs" file.
Actual: I am seeing this error: ReferenceError: userProperties is not defined
You want to use userProperties with the value, which is given in the function of onEdit, at the function of onEditOfH3, when onEdit is run.
You want to understand about the specification of the files in one GAS project.
If my understanding is correct, how about this answer? Please think of this as just one of several answers.
About all files in one GAS project:
At the project of Google Apps Script, all files in the project are used as one project. Namely, for example, when the following sample script is run in the file of Code.gs,
function myFunction() {
for (var i in this) {
if (typeof this[i] == "function") {
Logger.log(i)
}
}
}
all functions in all files in the project are returned. From this, it is found that when a global variable is declared at the file of Code.gs, this variable can be used at other file in the same project. At the following pattern 1, this is used.
Pattern 1:
In this pattern, userProperties is declared as the global variable.
Modified script:
Code.gs
var userProperties; // This is declared as the global variable.
function onEdit(e){
totalHoursLoggedForStory_today = Number(e.range.getSheet().getRange("H3").getValue()) + Number(e.range.getSheet().getRange("H4").getValue()) + Number(e.range.getSheet().getRange("H5").getValue());
userProperties = PropertiesService.getUserProperties(); // Modified
var newProperties = {'hoursLogged': totalHoursLoggedForStory_today };
userProperties.setProperties(newProperties);
onEditOfH3(e);
}
23546.gs
This is not required to be modified.
Pattern 2:
In this pattern, userProperties is added to the object of e. And the value is used as e.userProperties in the function of onEditOfH3. If you don't want to use the global variable, how about this? Also, userProperties can be sent as another argument.
Modified script:
Code.gs
function onEdit(e){
totalHoursLoggedForStory_today = Number(e.range.getSheet().getRange("H3").getValue()) + Number(e.range.getSheet().getRange("H4").getValue()) + Number(e.range.getSheet().getRange("H5").getValue());
var userProperties = PropertiesService.getUserProperties();
var newProperties = {'hoursLogged': totalHoursLoggedForStory_today };
userProperties.setProperties(newProperties);
e.userProperties = userProperties; // Added
onEditOfH3(e);
}
23546.gs
function onEditOfH3(e){
// var sh = SpreadsheetApp.getUi(); // In your whole script, this might be declared at elsewhere.
if (e.range.getA1Notation() == "H3") {
var temp = e.userProperties.getProperty('hoursLogged'); // Modified
sh.alert(temp);
}
}
Reference:
Script Projects
Doesn't this:
function onEditOfH3(e){
if (e.range.getA1Notation() == "H3") {
var temp= userProperties.getProperty('hoursLogged');
sh.alert(temp);
}
have to be like this:
function onEditOfH3(e){
if (e.range.getA1Notation() == "H3") {
var temp= PropertiesService.getUserProperties().getProperty('hoursLogged');
sh.alert(temp);
}
I have a Google spreadsheet file with almost 2000 rows of URL such as this one:
https://docs.google.com/uc?id=0B4ptELk-D3USblk1aWd1OWowRWs
Each URL contains an image, stored in Google Drive. My question is: How can I transform this link ( https://docs.google.com/uc?id=0B4ptELk-D3USblk1aWd1OWowRWs) to a file name? For instance, I would like to know if it could be a /something/folder/Photofile1.jpg.
Is there anyway of doing this?
Try script:
function TESTgetFileName() {
Logger.log(getFileName('0B4ptELk-D3USVi1NZ3ZGbkhqYXc'));
// ^^^^^^^^^^ file ID ^^^^^^^^^
}
function getFileName(id) {
var file = DriveApp.getFileById(id);
var fileName = file.getName();
var strFolders = getFolders(file);
return strFolders + '/' + fileName;
}
function getFolders(object) {
var folders = object.getParents();
if (!folders.hasNext()) { return 'My Drive'; }
var folder = folders.next();
var folderNames = [];
while (folder.getParents().hasNext()) {
var folderName = folder.getName();
folderNames.unshift(folderName);
folder = folder.getParents().next();
}
return folderNames.join('/');
}
Script function will return the result:
0B4ptELk-D3USVi1NZ3ZGbkhqYXc → My Drive/something/folder/Photofile1.jpg
Tests
I opened script editor, selected function TESTgetFileName and get the result
My Drive/Detalhes_Farmacia.Fotografia_Fachada_1.JPEG.
This function can be run from script, not directly from spreadsheets. When you try using it as custom formula from sheet, it throws error:
You do not have permission to call getFileById (line 8).
So better use it from script to get data and then write the result to the sheet.
I have a fairly basic spreadsheet that uses some Google Scripts to accomplish various tasks. I was trying to cleanup the interface for the end user, and decided to implement the Google Picker. Originally the user had to manually import a CSV into the spreadsheet. The new goal here is to select the CSV via the Google Picker, upload it, import it, then delete it. I already have all the code working to import it and delete it. I just worked up the code for the picker, and it seems to work fine. However, and I think I'm just missing something small, how do I pass the File ID back from the Picker.html to my Google Scripts in order to continue my process?
If it helps, I'm using the basic callback provided in the Google documentation right now. I'm assuming this is where the change will be made. Just not sure what to do.
function pickerCallback(data) {
var action = data[google.picker.Response.ACTION];
if (action == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
var id = doc[google.picker.Document.ID];
var url = doc[google.picker.Document.URL];
var title = doc[google.picker.Document.NAME];
document.getElementById('result').innerHTML =
'<b>You chose:</b><br>Name: ' + title + '<br>ID: ' + id;
} else if (action == google.picker.Action.CANCEL) {
document.getElementById('result').innerHTML = 'Picker canceled.';
}
}
This should probably work:
In your pickerCallback(data) function:
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
google.script.run
.withSuccessHandler(useData) // this will call the google apps script function in your Code.gs file
.doSomething(fileId); // this is a function in your JavaScript section where you will do something with the code you got from your apps script function
}
function useData(data) {
// do something with the data
}
In Code.gs, create a function to handle the input from the picker:
function doSomething(fileId) {
// do an operation in Drive with the fileId
var file = DriveApp.getFileById(fileId);
var fileName = file.getName();
return fileName;
}
First of all, open the chrome developer console when you are running this so you can see any errors that happen client side (when the picker is active). You can also use console.log to report any variable values in the Chrome console.
secondly, the call to the server works asynchronously, so it means that in your code, you'll get your message 'script was run', when it fact it hasn't yet. All that's happened is that google.script.run has asked for your server side function to execute.
That's why you have withSuccessHandler and withFailureHandler.
so you should do
google.script.run
.withSuccessHandler (function (response) {
document.getElementById('result').innerHTML = 'it worked'
})
.withFailureHandler (function (err) {
document.getElementById('result').innerHTML = err;
})
.justatest (fileId);
and back in the server script
function justatest(fileId) {
Logger.log (fileId);
}
If you then go back and look in the script log file, you should see the fileId.