Convert web document objects to a Spreadsheet function - google-apps-script

Using and spreadsheet, I have an HTML web that fills some text boxes and create some google charts when a csv file is dropped (this is not a Form)
I need to make a function that let me parse the value of the text boxes in order to fill a spreadsheet, this is my code so far:
Tablas.html (I am trying to pass all the document object as a parameter)
<input id="cmd" onclick="formSubmit()" type="button" value="Descargar SnapShot">
<script type="text/javascript">
function formSubmit() {
google.script.run.getValuesFromForm(document);
}
And the gs Script: (With the document as a parameter, i am trying to recover a text box named "modequ" to fill a new row in the Spreadsheet)
function getValuesFromForm(document){
var ssID = "12GvIStMKqmRFNBM-C67NCDeb89-c55K7KQtcuEYmJWQ",
sheet = SpreadsheetApp.openById(ssID).getSheets()[0],
modequ = document.getElementById("modequ").value;
sheet.appendRow([modequ]);
}
Is there any way to connect the all the document objects in the page made with the spreadsheet so i can append and process it? I though if maybe if i pass the all the document object this would be possible.
Regards

The document.getElementById() method returns a reference from the id attribute from your HTML, it needs to be inside your formSubmit() function:
function formSubmit() {
var modequ = document.getElementById('modequ').value;
google.script.run.getValuesFromForm(modequ);
}
This way you can get all the values individually and then pass them as parameter e.g. google.script.run.getValuesFromForm(modequ, tipmoto, smr)
However, if you want to pass all the form elements and then get them by name, you can do something like this:
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form id="form" name="form">
<input name="modequ" type="text">
<input name="tipmoto" type="text">
<input name="series" type="text">
<input id="cmd" onclick="formSubmit()" type="button" value="Descargar SnapShot">
</form>
</body>
</html>
<script type="text/javascript">
function formSubmit(){
google.script.run.getValuesFromForm(document.forms[0]);
}
</script>
GS:
function getValuesFromForm(res){
var ssID = '12GvIStMKqmRFNBM-C67NCDeb89-c55K7KQtcuEYmJWQ',
sheet = SpreadsheetApp.openById(ssID).getSheets()[0];
sheet.appendRow([res.modequ, res.tipmoto, res.series]);
}

Related

Uploading An Image With Google Apps Script To A GSheet - Passing Values To And From HTML Service Modal Dialog

I'm trying to trigger a file upload off of a Google Sheet, taking the uploaded file, add it to a Google Drive folder, and then return the URL of the uploaded file and place it in a cell on the Sheet. I'm currently triggering the file upload by using a checkbox. Once you set the checkbox to TRUE, it'll pop up a dialog box with a file upload input field. This is triggered by an installed onEdit function. Also, info on the row in the sheet will be used to name the newly uploaded file. This info will be input manually on the sheet.
I get to the showModalDialog line, and the dialog box comes up just fine, but I can't figure out how to pass variables from the original function to the HTML service and then back again (with the file) to upload to Drive, set the name, and put the URL back on the sheet.
Here's the first function in Code.gs, receiving values from the onEdit function:
function addFile(ss,ui,row,total) { \\Triggered if edited cell is in column 25 & value is TRUE
Logger.log('add file function');
var name = ss.getRange(row,1).getDisplayValue();
var date = ss.getRange(row,3).getDisplayValue();
var filename = 'Row ' + row + ' - ' + name + ' - ' + date + ' - ' + total;
var htmlTemp = HtmlService.createTemplateFromFile('Index');
htmlTemp.fName = filename;
htmlTemp.position = row;
var html = htmlTemp.evaluate().setHeight(76).setWidth(415);
ui.showModalDialog(html, 'Upload');
Logger.log('end of add file function');
}
And here's what's in Index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_center">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<form>
Please upload image below.<br /><br />
<input type="file" name="upload" id="file" accept="image/*,.pdf" />
<input type="button" value="Submit" class="action" onclick="formData(this.parentNode)" />
<input type="button" value="Close" onclick="google.script.host.close()" />
</form>
<script>
function formData(obj){
var newFileName = <? fName ?>;
var rowNum = <? position ?>;
google.script.run.withSuccessHandler(closeIt).upload(obj,newFileName,rowNum);
}
function closeIt(e){
console.log(e);
google.script.host.close();
};
</script>
</body>
</html>
And here's the return function on Code.gs:
function upload(obj,newFileName,rowNum) {
Logger.log('upload function');
var upFile = DriveApp.getFolderById('[folderid]').createFile(obj).setName(newFileName);
var fileUrl = upFile.getUrl();
Logger.log(fileUrl);
var urlCell = SpreadsheetApp.getSheetByName('sheet name').getRange(rowNum,26);
urlCell.setValue('=HYPERLINK("' + fileUrl + '","View image")');
}
Running this code, the dialog box comes up just fine, and I'm able to select a file for upload. However, clicking the Submit button does nothing, and the box stays up until I X it out or hit the Cancel button. The logs only get so far as 'end of add file function' and never gets to the upload function. Should the google.script.run.withSuccessHandler line close the dialog box, or is something else needed to confirm / get the file and close the box?
I've been searching online and have found a number of posts relating to this, but none seem to address this specific issue. This is also pretty much a frankenstein of code I've cobbled together from those posts, so it's possible there's just something that doesn't belong in there and if that is the case I do apologize. Any help would be appreciated; thanks!
[Edit: the submit button wasn't opening a separate tab because I was using <input type="button"> instead of <button>.]
According to the documentation [1] in the “Parameters and return values” part,
if you’re going to send the form object as a parameter “it must be the function’s only parameter”. So you should send the parameters inside the form, using inputs of types “hidden” or “text”, then, from code.gs you can retrieve the input data of the Form object.
Another thing stated in the documentation [1] in the “form” section, is that you need to disable the default submit action with preventFormSubmit function.
Another problem is that the correct way of printing the variables passed to the template are using <?= ?> instead of <? ?> which works to execute code but not to print variables. [2]
Your “addFile” function is all right. Below is the code i've tested on my environment and I was able to upload an image successfully and print the url in the sheet.
Index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_center">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
</head>
<body>
<form id="myForm">
Please upload image below.<br /><br />
<input type="hidden" name="fname" id="fname" value="<?= fName ?>"/>
<input type="hidden" name="position" id="position" value="<?= position ?>"/>
<input type="file" name="file" id="file" accept="image/jpeg,.pdf" />
<input type="button" value="Submit" class="action" onclick="formData(this.parentNode)" />
<input type="button" value="Close" onclick="google.script.host.close()" />
</form>
<script>
//Disable the default submit action using “func1”
window.onload=func1;
function func1() {
document.getElementById('myForm').addEventListener('submit', function(event) {
event.preventDefault();
});
}
function formData(obj){
google.script.run.withSuccessHandler(closeIt).upload(obj);
}
function closeIt(e){
console.log(e);
google.script.host.close();
};
</script>
</body>
</html>
Code.gs (upload function):
function upload(obj) {
//Retrieve the input data of the Form object.
var newFileName = obj.fname;
var rowNum = obj.position;
var blob = obj.file;
var upFile = DriveApp.getFolderById('[folderid]').createFile(blob).setName(newFileName);
var fileUrl = upFile.getUrl();
var urlCell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1').getRange(rowNum,5);
urlCell.setValue('=HYPERLINK("' + fileUrl + '","View image")');
}
[1] https://developers.google.com/apps-script/guides/html/communication
[2] https://developers.google.com/apps-script/guides/html/templates

Modifying an existing Calendar Event from HtmlService input

I'm trying to add a "Sign Up" link to a Google Calendar Event where upon clicking the user is prompted via HtmlService to submit their email address. Their email address is then added to the event.
Here's a similar example. What I'd like to do differently is use HtmlService to have the user input their email address, which then is passed back to GAS to be added to the Calendar Event in question. That way they can choose the email they want (instead of whatever Session.getActiveUser().getEmail() returns) to sign up with. (and by sign up, I mean get added to the guest list - they still have to accept the invite, but that's fine).
Is this possible? I'm not seeing any examples of this so maybe there's a better way?
I am starting to tear out what little hair I have. I've included my latest sample code, where I pass the event object into the HTML template. It's not throwing an error, but it's not working either. Thank you in advance!!
Code.gs:
function doGet(event) {
// // shorten the event parameter path;
var param = event.parameter;
// // get the calendar event id passed in the query parameter
var eventId = param.eId;
var calId = param.calId;
var cal = CalendarApp.getCalendarById(calId);
var t = HtmlService.createTemplateFromFile('Index');
t.eObj = cal.getEventById(eventId);
return t.evaluate();
}
function addEmail(emObj,myForm){
var guestEmail = myForm.user;
emObj.addGuest(guestEmail)
}
and Index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function update() {
alert("Success!");
}
</script>
</head>
<body>
<form id="myForm">
<input id="userEmail" name="user" type="text" />
<input type="button" value="Submit" onClick="google.script.run.withSuccessHandler(update).addEmail(eObj,this.form)" />
</form>
</body>
</html>
You don't have scriptlets in your html file, so you don't need to evaluate a template. I've added another 2 input fields for the calId and eventId. They get replaced in the HTML before being served. Then the event ID and Cal ID are passed back in the form object.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function update() {
alert("Success!");
}
</script>
</head>
<body>
<form id="myForm">
<input id="userEmail" name="user" type="text" />
<input name="calId" type="text" style="display:none"
value="zzz_calID_zzz"/>
<input name="eventId" type="text" style="display:none"
value="zzz_eventID_zzz"/>
<input type="button" value="Submit" onClick="google.script.run
.withSuccessHandler(update)
.addEmail(this.form)" />
</form>
</body>
</html>
doGet:
function doGet(event) {
// // shorten the event parameter path;
var param = event.parameter;
// // get the calendar event id passed in the query parameter
var eventId = param.eId;
var calId = param.calId;
var t = HtmlService.createHtmlOutputFromFile('Index').getContent();
t = t.replace('zzz_calID_zzz',calId);
t = t.replace('zzz_eventID_zzz',eventID);
return HtmlService.createHtmlOutput(t);
}
Server code:
function addEmail(myForm){
var cal = CalendarApp.getCalendarById(myForm.calId);
var event = cal.getEventById(myForm.eventId);
var guestEmail = myForm.user;
event.addGuest(guestEmail)
}

How to send inputs from google spreadsheet sidebar into sheet script function?

I want to have 3 text fields with labels and a button on sidebar, clicking the button should send content of text fields to spreadsheet script function for further processing. I know how to create and display the sidebar, also how to trigger script function with button click but have no idea how to send text fields content.
// SidePanel.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button onclick='f1()'>Update the address</button>
<script>
function f1() {
google.script.run.getAddress();
}
</script>
</body>
</html>
// display sidebar in gs
function showSidebar(){
var html = HtmlService.createHtmlOutputFromFile('SidePanel').setTitle('Helper').setWidth(100);
SpreadsheetApp.getUi().showSidebar(html);
}
Here is an example that will help you understand how to send values from the sidebar to the google sheet
Html Code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button onclick='f1()'>Update the address</button>
<!-- Create a input field to except a value form user, in this case there name -->
Your Name:
<input type="text" id="name"><br>
<!-- Create a button to send the value to the spreadsheet -->
<button onclick='sendName()'>Send Name</button>
<script>
function f1() {
google.script.run.getAddress();
}
function sendName(){
//Get the value of the input field
var name = document.getElementById("name").value
//Log the value of input field in the web browser console (usually used for debugging)
console.log(name)
//Send the value of the text field as a arugment to the server side function.
google.script.run.enterName(name)
}
</script>
</body>
</html>
The HTML code above use the input field to get values from the user. You can access the value of the input field using DOM methods. The value of the text field is stored in the var name in function sendNames(). This is passed to the google script function as an argument google.script.run.enterName(name).
Your google script (aka server-side code)
function showSidebar(){
var html = HtmlService.createHtmlOutputFromFile('SO_sideBar_Example').setTitle('Helper').setWidth(100);
SpreadsheetApp.getUi().showSidebar(html);
}
// Sets the value of A1 cell to value entered in the input field in the side bar!
function enterName(name){
var ss = SpreadsheetApp.getActive()
var sheet = ss.getActiveSheet()
sheet.getRange("A1").setValue(name)
}
In the above server side code,function enterName() receives the user input in the argument name, which is entered in cell A1.
It is good practice to use withSuccessHandler() and withFailureHandler() as detailed here. To handle the success or failure of the server side code.

Google apps script get user input with no length limit

I want to take user input (HTML specifically) using either:
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Paste HTML below');
or
var input = Browser.inputBox('Paste HTML below', Browser.Buttons.OK_CANCEL);
These work fine for small inputs, however when copying over the entire HTML for a page of interest an error occurs (in each case). This error cannot be caught, it simply crashes the script.
Do you know why this is happening? I can't find anything in the docs that mention limits on input size.
Any experience doing this a different way?
Edit: as per a suggestion in the comments, I have tried another method (below). This also fails (with no error message) when passed large input.
First I set up Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Paste Sitemap Content Below
<textarea id="user-input-box" rows="4" cols="50"></textarea>
<script>
function logToConsole() {
var userInput = document.getElementById("user-input-box").value;
google.script.run.doSomething(userInput);
}
</script>
<input type="button" value="Close" onclick="logToConsole();google.script.host.close();" />
</body>
</html>
Then in file Code.gs
function testDialog() {
var html = HtmlService.createHtmlOutputFromFile('Page')
.setWidth(400)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(html, 'My custom dialog');
}
function doSomething(userInput){
Logger.log(userInput);
}
I just ran into the same problem and couldn't log the error. In my case as is yours, you're calling your logToConsole() function and then directly after you're closing the dialog by using google.script.host.close();
google.script.host.close() is the problem. For some reason it can cancel the script execution - this typically happens when you're sending a lot of data back. The trick is to use a successHandler when you call your script which then calls google.script.host.close(). This way, the data transfer from the dialog finishes correctly and when you call withSuccessHandler(), that callback closes the dialog. Try this amendment to your code:
<script>
function logToConsole() {
var userInput = document.getElementById("user-input-box").value;
google.script.run.withSuccessHandler(closeDialog).doSomething(userInput);
}
function closeDialog() {
google.script.host.close();
}
</script>
<input type="button" value="Close" onclick="logToConsole()" />

create a new row in google spreadsheet from an html form

I am medical researcher, and I am creating a database of my patients, I have a form in html and want the variables obtained were stored in a spreadsheet of google, so far I have only this:
spreadsheet:
my spreadsheet in google
code.gs:
function addProduct() {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(['name', 'age']);
}
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Name and age!
<input type=text name=name id=name>
<input type=number name=age id=age>
<input type=submit onclick=google.script.run.addProduct()>
</body>
</html>
I dont know how to link the variables in the html form, to the code.gs to enter the answers in a new row with the sheet.appendRow
I will appreciate your help,
thanks
Your input tags are not in a form, so you can't get the form element as a whole. Which you don't need to do, but it's worth mentioning because there are multiple ways you can structure things.
You can use what's called the DOM to get the values out of the input tags.
<body>
Name and age!
<input type=text name=name id=name>
<input type=number name=age id=age>
<input type=submit onclick="myClientSideJavaScriptFunction()">
</body>
<script>
function myClientSideJavaScriptFunction() {
var inputOneValue = document.getElementById('name').value;
var inputTwoValue = document.getElementById('age').value;
google.script.run
.addProduct(inputOneValue, inputTwoValue);
};
</script>
Code.gs
function addProduct(x1, anythingYouWantToNameIt) {
var myArray = [];
myArray.push(x1);
myArray.push(anythingYouWantToNameIt);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(myArray);
};