Why google.script.run does not work from HTML? [duplicate] - html

When I click submit focus returns to spreadsheet and data get loaded, but dialog box does not get closed. I used google.script.host.close(), but that won't pass focus back to spreadsheet.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form >
Select Client:
<div>
<select id="optionList" name="client">
</select>
</div>
Select Action:
<div>
<select id="actionList" name="action">
</select>
</div>
Username:
<input type="text" name="username"> <br />
Password:
<input type="password" name="password"> <br />
<input type="button" value="OK" onclick="google.script.run.callNumbers(this.parentNode);google.script.host.editor.focus();" />
</form>
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function () {
google.script.run.withSuccessHandler(buildOptionList)
.getClients();
google.script.run.withSuccessHandler(buildActionList)
.getActions();
});
function buildOptionList(clients) {
var list = $('#optionList');
list.empty();
for (var i = 0; i < clients.length; i++) {
list.append(new Option(clients[i]));
}
}
function buildActionList(actions) {
var list = $('#actionList');
list.empty();
for (var i = 0; i < actions.length; i++) {
list.append(new Option(actions[i]));
}
}
</script>
</html>
function html(){
var html = HtmlService.createHtmlOutputFromFile('load');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Input API Creddentials');
}
I want to get focus back to Spreadsheet after closing dialog. I have tried using google html template instead dialog within sandbox mode, but that didn't work.
When I use google.script.host.editor.focus() and google.script.host.close() together it didn't send focus back to sheet.

I just use success handler to close my dialog after calling function and that worked.
<input type="button" value="OK" onclick="google.script.run.withSuccessHandler(google.script.host.close).callNumbers(this.parentNode);google.script.host.editor.focus();" />
This will close dialog window and return focus on spread sheet.

Related

Unable to submit more than one file to google script web project

I have created a Google Script Web project and added a HTML form which is having multiple file input fields and a few text input fields. The form is working and submitting all the text input every time but having an issue with the file input fields.
When my form is having only one file input field then all the text inputs and the file data are submitted to the server and can save the file.
When my form is having two or more file input fields then all the text inputs are submitted to the server side but the file fields are having empty object which is {}
The form looks like below:
<form id="msForm">
.......
<input type="file" class="custom-file-input" name="certificateFile" accept="application/pdf" required >
<input type="file" class="custom-file-input" name="otherDocuments" accept="application/pdf" required >
.....
<input type="button" name="next" class="next action-button" value="Submit" />
</form>
JS has the following to submit the form:
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
$(document).ready(function(){
$(".next").click(function(){
if($(this).val()=="Submit") {
google.script.run
.withSuccessHandler(successFormSubmit)
.withFailureHandler(failedFormSubmit)
.processForm($(this).closest("form")[0]);
}
});
});
The server side function in the Code.gs file:
function processForm(formObject) {
console.log(formObject.certificateFile);
console.log(formObject.otherDocuments);
}
Application is deploying and testing with following project settings:
Post edit:
The issue has been fixed by Google in this bug reported
This issue does seem to be a bug. While Google is looking at it, I suggest you a workaround:
Only logging the bytearray server-side seems to be impacted by the bug, you can still create all files from the blobs passed on form submisison with DriveApp.createFile().
If you need a server-side check to make sure the file blob is not empty, you can create in your form a hidden additional element of a type that is not "file" and use it a placeholder to send information to the serverside.
Sample:
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form id="msForm">
<input type="file" class="custom-file-input" name="certificateFile" accept="application/pdf" required >
<input type="file" class="custom-file-input" name="otherDocuments" id="otherDocuments" accept="application/pdf" required >
<input type="text" readonly="true" name="otherDocumentsName" id="otherDocumentsName" style="display: none;">
<input type="button" id="submitBtn" name="next" class="next action-button" value="Submit" />
</form>
<script>
document.getElementById('submitBtn').addEventListener('click',function(e) {
console.log(this.parentNode)
document.getElementById("otherDocumentsName").value = document.getElementById("otherDocuments").value;
google.script.run.withSuccessHandler(successFormSubmit).withFailureHandler(failedFormSubmit).processForm(this.parentNode);
})
function successFormSubmit(data){
console.log("success");
}
function failedFormSubmit(data){
console.log("failed");
}
</script>
</body>
</html>
code.gs
function doGet() {
var html = HtmlService.createHtmlOutputFromFile('index');
return html.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function processForm(data){
var blob1 = data.certificateFile;
var file1 = DriveApp.createFile(blob1);
file1.setName("certificateFile");
if (data.otherDocumentsName !== "") {
console.log("not empty")
var file2 = DriveApp.createFile(data.otherDocuments);
file2.setName("otherDocuments");
}
else{
console.log("empty");
}
}

Custom dialog box isn't showing any output

I'm using the following scripts for a custom dialog box to make data entries into a specific range of cells. (source: https://spreadsheet.dev/custom-dialog-in-google-sheets)
Here is the HTML part:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function submitForm() {
google.script.run.appendRowFromFormSubmit(document.getElementById("Stunde eintragen"));
document.getElementById("form").style.display = "none";
document.getElementById("Danke").style.display = "block";
}
</script>
</head>
<body>
<div>
<div id="form">
<form id="Stunde eintragen">
<label for="Datum">Datum</label>
<input type="date" id="Datum" name="Datum"><br><br>
<label for="Inhalt">Inhalt</label>
<input type="text" id="Inhalt" name="Inhalt" size="60"><br><br>
<label for="Lehrkraft">Lehrkraft</label>
<select id="Lehrkraft" name="Lehrkraft">
<option value="Alexander Michaelis">Alexander Michaelis</option>
<option value="Thomas Weider">Thomas Weider</option>
</select>
<div>
</br>
<label for="Ausfall">Stunde ausgefallen?</label><br>
<input type="radio" id="E" name="Ausfall" value="E">
<label for="E">Entschuldigt</label><br>
<input type="radio" id="UE" name="Ausfall" value="UE">
<label for="UE">Unentschuldigt</label><br><br>
<input type="button" value="Eintragen" onclick="submitForm();">
</form>
</div>
</div>
<div id="Danke" style="display: none;">
<p>Die Stunde wurde eingetragen!</p>
</div>
</body>
</html>
And here is the GAS part:
//#OnlyCurrentDoc
function onOpen() {
SpreadsheetApp
.getUi()
.createMenu("Klassenbuch")
.addItem("Stunde eintragen", "showFeedbackDialog")
.addToUi();
}
function showFeedbackDialog() {
var widget = HtmlService.createHtmlOutputFromFile("Form.html");
SpreadsheetApp.getUi().showModalDialog(widget, "Stunde eintragen");
}
function appendRowFromFormSubmit(form) {
var row = [form.name, form.feedback, form.rating];
SpreadsheetApp.getActiveSheet().appendRow(row);
}
By submitting the form I want to have the data copied into a specific range (for example A7:A, B7:B, C7:C, D7:D with row 6 for the labels) and everytime I use the script it should jump in the next row.
But unfortunately the script doesn't show any output.
Can anybody help?
You can't transmit objects, but you can transmit values, even if they are in array like this
html :
function submitForm() {
var form = document.getElementById("Stunde eintragen")
google.script.run.appendRowFromFormSubmit([form.Datum.value , form.Ausfall.value , form.Inhalt.value]);
document.getElementById("form").style.display = "none";
document.getElementById("Danke").style.display = "block";
}
and gs
function appendRowFromFormSubmit(data) {
SpreadsheetApp.getActiveSheet().appendRow(data);
}
Note that in your form has no feedback and no rating !!

Make submit button close dialog and return focus to spreadsheet google app script

When I click submit focus returns to spreadsheet and data get loaded, but dialog box does not get closed. I used google.script.host.close(), but that won't pass focus back to spreadsheet.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form >
Select Client:
<div>
<select id="optionList" name="client">
</select>
</div>
Select Action:
<div>
<select id="actionList" name="action">
</select>
</div>
Username:
<input type="text" name="username"> <br />
Password:
<input type="password" name="password"> <br />
<input type="button" value="OK" onclick="google.script.run.callNumbers(this.parentNode);google.script.host.editor.focus();" />
</form>
</body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function () {
google.script.run.withSuccessHandler(buildOptionList)
.getClients();
google.script.run.withSuccessHandler(buildActionList)
.getActions();
});
function buildOptionList(clients) {
var list = $('#optionList');
list.empty();
for (var i = 0; i < clients.length; i++) {
list.append(new Option(clients[i]));
}
}
function buildActionList(actions) {
var list = $('#actionList');
list.empty();
for (var i = 0; i < actions.length; i++) {
list.append(new Option(actions[i]));
}
}
</script>
</html>
function html(){
var html = HtmlService.createHtmlOutputFromFile('load');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Input API Creddentials');
}
I want to get focus back to Spreadsheet after closing dialog. I have tried using google html template instead dialog within sandbox mode, but that didn't work.
When I use google.script.host.editor.focus() and google.script.host.close() together it didn't send focus back to sheet.
I just use success handler to close my dialog after calling function and that worked.
<input type="button" value="OK" onclick="google.script.run.withSuccessHandler(google.script.host.close).callNumbers(this.parentNode);google.script.host.editor.focus();" />
This will close dialog window and return focus on spread sheet.

Google sheets sidebar form - set default values

I am trying to make a spreadsheet sidebar that allows a user to input data to create records, as well as edit them. So far I understand how to create the sidebar and display it. I've got a working form that can submit values.
What I am struggling with is how to pre-populate the forms. Form instance some records are associated with others, and I'd like to have a hidden field to store and eventually submit the associated id. Eventually users should also be able to edit records and I'd like to use the same form and just populate the fields and reuse the same submission flow.
I've tried a few different things found on here and other places, but nothing seems to work.
Here is the HTML for the sidebar template
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<style>
</style>
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
$('#accountId').val(<? data.accountId ?>);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(alertSuccess).createContact(formObject);
}
function alertSuccess(message) {
var div = document.getElementById('alert');
div.innerHTML = "<p>" + message + "</p>";
google.script.host.close();
}
</script>
</head>
<body>
<p>Enter Contact Info</p>
<form id="contact" onsubmit="handleFormSubmit(this)">
Account Id: <br>
<input type="number" name="accountId" value="0" id="accountId" /><br>
Name:<br>
<input type="text" name="name"/><br>
Phone Number:<br>
<input type="text" name="phone"/><br>
Email:<br>
<input type="email" name="email"/><br>
Contact Type:<br>
<input type="radio" name="type" value="emergency" checked> Emergency<br>
<input type="radio" name="type" value="guardian" checked> Guardian<br>
<input type="radio" name="type" value="other" checked> Other<br>
<input type="submit" value="Submit" />
</form>
<div id="alert"></div>
</body>
</html>
And the accompanying .gs file:
var AlternativeContact = ObjectModel("AlternativeContacts");
function newContact() {
var htmlOutput = HtmlService.createTemplateFromFile("new_contact");
var id = ACCOUNT_MANAGER.getRange("M4").getValue();
htmlOutput.data = {accountId: id};
UI.showSidebar(htmlOutput.evaluate());
}
function createContact(contactJSON) {
var newContact = new AlternativeContact(contactJSON);
newContact.save();
return "Success!";
}
The first line that uses ObjectModel is creating and ORM around the data sheet.
Thanks for the help!
Couple changes and it seems to be working in a basic way.
First, in the scriptlet, i needed to us the printing tag. so use in stead of . This was causing the value to not be used in the rendered template.
Second, I changed my jQuery to:
$(document).ready(function () {
$("input#accountId").val(<?= data.accountId ?>);
});
If anyone is able to answer, I'd be curious why using the $(document).ready is needed. Doesn't everything in the get run? is it an order of operation thing?

Login button is not working while pressing enter in a pop up window form in chrome extension

Hi I have created a pop up window containing a form asking the user to enter email and password.And there is a log in button.Usually in most of the forms, after entering all details and pressing 'enter', the submit button will be automatically clicked.But in this case,only when I click the login button it works.I want it to work on pressing 'enter' in keyboard.I know that this is a simple question.But I can't figure it out why is this happening.Please help me
Here is my userinfo.html(pop up window)
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<b>Enter your Email ID and Password</b><br><br>
<form id="userinfo">
<label for="user"> Email : </label>
<input type="text" id="user" /><span id="semail"></span>
<br><br>
<label for="pass">Password : </label>
<input type="password" id="pass" />
<br>
<br>
<input type="button" id="login" value="Log In"/>
</form>
</body>
</html>
Here is my test.js
window.addEventListener('DOMContentLoaded', function() {
var user = document.querySelector('input#user');
var pwd = document.querySelector('input#pass');
var login = document.querySelector('input#login');
login.addEventListener('click', function() {
var userStr = user.value;
var pwdStr = pwd.value;
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.login(userStr,pwdStr); });
window.close();
});
});
In order for a submit event to be triggered on ENTER the form must have a submit button.
In your particular case, you need to revent the default behaviour of your form, since you want to handle it "manually" using the background-page.
In summary, the following steps are required:
Change the button type from button to submit.
Register a listener for the form's submit event. (Note: this will be triggered on both button-click and ENTER.)
Prevent the default behaviour on form-submit.
Delegate the login-handling to the background-page (through its login method.
Here is the new code:
test.html
<h4>Enter your Email ID and Password</h4>
<form id="userinfo">
<label for="user">E-mail: </label>
<input type="text" id="user" required />
<br />
<label for="pass">Password: </label>
<input type="password" id="pass" required />
<br />
<br />
<input type="submit" id="login" value="Log In" />
</form>
test.js
window.addEventListener('DOMContentLoaded', function () {
var form = document.querySelector('form#userinfo');
var user = document.querySelector('input#user');
var pass = document.querySelector('input#pass');
/* Register a listener on the form's `submit` event */
form.addEventListener('submit', function (evt) {
/* Prevent the event from being handled by the browser */
evt.preventDefault();
var userStr = user.value;
var passStr = pass.value;
/* Delegate login-handling to background-page */
chrome.runtime.getBackgroundPage(function (bgPage) {
bgPage.login(userStr, passStr);
});
window.close();
});
});
See, also, this short demo.