HTML Service - Uncaught NetworkError: Form submission failed - google-apps-script

I am working through the google example code for HTML Service: Communicate with Server Functions.
I can't get the sample code to work for "Forms'. Is there an error in the code or is it something in my browser config?
The code is -
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
index.html
<script>
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
<form id="myForm">
<input name="myFile" type="file" />
<input type="button" value="Submit"
onclick="google.script.run
.withSuccessHandler(updateUrl)
.processForm(this.parentNode)" />
</form>
<div id="output"></div>
The error in the debug windows of my browser is
Uncaught NetworkError: Form submission failed.
Thanks in advance. Will Brown.

This error is not due to a code problem at all, rather it is an interaction between a browser plug-in and Google's authentication services. See Issue 3339 and Issue 4394.
If you're using the LastPass password manager plugin, it must be disabled.
PS: #user3531933 - if you add your own answer, just leave a comment for me, and I'll happily delete this and leave it to you.

Related

There was an error during the transport or processing of this request. Error code = 10, Path = /wardeninit

I'm trying to pass an object (contents of a sheet row) to an apps script template. You can see the row in the screenshot.
my function in apps script contains:
var sendableRows = rows.filter(function (row) { //ONLY CHECKED ROWS.
return row['Index'] == true;
});
var sendableRow = sendableRows[0];
Logger.log('sendableRow '+ JSON.stringify( sendableRow));
var html = HtmlService.createTemplateFromFile('RowPopup');
html.row = JSON.stringify(sendableRow);
var h =html.evaluate();
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(h, 'Create Documents');
The logger statement produces:
sendableRow {"Index":true,"Timestamp":"2019-02-12T21:09:14.000Z","FROM":222222,"CONVERSATION":"THIS IS A TEST","ME":"","relativeRow":14,"absoluteRow":15}
My Rowpopup.html is :
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('forms');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
// the output from form goes to processDocBuildHtml
google.script.run
.withSuccessHandler(updateUrl)
.processRowPopupHTML(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Sent!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<div>
<label for="optionList">Click me</label>
<select id="optionList" name="email">
<option>Loading...</option>
</select>
</div>
<br>
<div>
</div>
<br>
<div>
<textarea name="message" rows="10" cols="30">
The cat was playing in the garden.
</textarea>
</div>
<div id="textboxes"></div>
<div id="insert"></div>
<input type="submit" value="Submit" />
</form>
<div id="output">
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="//rawgithub.com/indrimuska/jquery-editable-select/master/dist/jquery-editable-select.min.js"></script>
<link href="//rawgithub.com/indrimuska/jquery-editable-select/master/dist/jquery-editable-select.min.css" rel="stylesheet">
<script>
function getConversations() {
var jsonRow = <?= row ?>; //PASSED IN JSON
console.log('row');
var myObj = JSON.parse(jsonRow);
console.log(myObj['CONVERSATION']);
return myObj['CONVERSATION'];
}
</script>
</body>
When I run this I see:
Which shows some issue with "warden".
Also, I don't see the expected data outputted to console in:
console.log('row');
var myObj = JSON.parse(jsonRow);
console.log(myObj['CONVERSATION']);
What am I doing wrong?
Your client side code never calls getConversations, that is why you don't see it on the console. Among many ways to do this, you could add an IIFE to call that function by adding the following on between <script> tags
(function (){getConversations()}());
By the other hand, the referred error message on the Chrome Developers Tools Console occurs even with the simplest code like the following
function myFunction(){
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showModalDialog(html, 'Test')
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hello world!
</body>
</html>
So it's not you, it's Google
I know this answer is not related to this OP and the place I should post is not appropriate, but for the other people who reach this page in future, I leave an answer here because I struggled to solve similar problems.
I think this error means we cannot connect from an HTML file to the scripts written in Script Editor.
So basically you can ignore this error message(maybe. If not, tell me the correct feature.)
To me, the error has occurred when executing google.script.run.myFunction(). So, at the first, I thought the error prevents this execution. However, the error was completely unrelated to this execution. It was another problem and I detected why my issue had happened by using withFailureHandler(onFailure). It emits an error message. (See more information at https://stackoverflow.com/a/33008218/3077059)
As Mr. Rubén says "So it's not you, it's Google", this error can be replayed, easily. Please don't be puzzled by this message. The error message("There was an error during the transport or processing of this request. Error code = 10, Path = /wardeninit") is useless, I think.
Ruben's great post is this -> https://stackoverflow.com/a/54756933/3077059
You have only declared the function getConversations. It's not executed until call it ().
To execute directly on loading, try
(function getConversations(){})()
I had a similar problem. But in my case, most of my users didn't have the issue. Just some users in some PCs. Then I found out that, in these cases (about 10%), if they installed Firefox and ran the app, everything worked just fine. So that was my solution: suggest Firefox when this behavior occurred.
My solution: use versioned deployments of library scripts.
I had a similar issue where I was unable to run my own functions from the sidebar in Google Sheets. The issue seemed to be connected with using a library, even though the scripts that I was attempting to execute were not dependent on the library.
When the library was connected to the container script i couldn't get functions in the sidebar to execute. When I removed the library it all worked fine. I was using the head version of the library, meaning the most current development. I decided to try managing deployments and creating versions of the project. I added a Library deployment and version, then updated my library reference, and everything works again.
References:
Why does my apps script deployed as API executable return Permission Denied?
https://developers.google.com/apps-script/concepts/deployments
A descriptive alert from Google would be helpful.
To anyone getting this error. Try to run the code in another browser, Safari, or in guest mode.
In my case, it was probably some extension, I'm still not sure but I have already spent hours on this so I won't further investigate.

Control Flow Between Server and Client and Back to Server for Google Apps Script

I have a question about the control flow between some JavaScript code running as bound functions within a google spreadsheet - so server side - and a dialog (that happens to be Modal, but Modeless is the same) that is client side.
While the code examples below work fine in that the dialog successfully calls the server side function as per the line below, and the withSuccessHandler works too.
google.script.run.withSuccessHandler(success_callback).getCredentials(this.parentNode)
But what I actually want to achieve is for some server side code to carry on executing once the dialog has gone; ideally from the point the .showModalDialog() function was called, but I'd be happy just passing control back to any server-side function.
Some example software is below; don't forget this works, just not how I want it too! Essentially the event handler for a menu item created by the the OnOpen() function calls a modal dialog to prompt the user for security credentials.
var html = HtmlService.createHtmlOutputFromFile('authorization_dialog');
SpreadsheetApp.getUi()
.showModalDialog(html, 'Authorization Dialog');
The HTML file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
Authorization Code:
<input type="text" name="authorization_code"><br><br>
Account ID:
<input type="text" name="account_id"><br><br>
Enter account details...
<br>
<br><br>
<input type="button" value="OK"
onclick="google.script.run.withSuccessHandler(success_callback).getCredentials(this.parentNode)" />
<input type="button" value="Close"
onclick="google.script.host.close()" />
</form>
<script>
// Using this call back prevents the need to hit the Close Button after OK.
function success_callback() {
google.script.host.close(); // Close the dialog.
}
</script>
</body>
</html>
If you don't need a response from the server-side function, simply omit 'withSuccessHandler';
function func_client(){
google.script.run.func_server();
google.script.host.close();
}
In this case, the server-side code will continue executing without locking your client's UI - you can call any other functions inside 'func_server'.
If you'd like to process a response from the first function call, call the second function from 'success_callback'. The dialog will be closed without waiting for the google.script.run to complete, but the server code will continue executing.
In the example below, the 1st server function passes form data back to the client where 'success_callback' immediately invokes another server function that takes a while to complete (it logs each file in my Google Drive);
Client:
<form id="form">
.....
<input type="submit" id="ok" value="OK" />
<input type="button" value="Close" onclick="google.script.host.close()" />
.....
</form>
<script>
window.onload = function(){
document.getElementById("form")
.addEventListener("submit", function(e){
e.preventDefault();
google.script.run
.withSuccessHandler(success_callback)
.logFormData(this);
});
}
function success_callback(response) {
console.log(response);
google.script.run.scanFiles();
google.script.host.close(); // Close the dialog.
}
</script>
Server:
function showDialog(){
var ui = SpreadsheetApp.getUi();
//IMPORTANT: client-side scripts won't be executed
//without calling evaluate() on the HtmlTemplate object before passing it to UI;
var template = HtmlService.createTemplateFromFile("dialog");
var html = template.evaluate();
ui.showModalDialog(html, "dialog");
}
function logFormData(formData){
return formData;
}
function scanFiles() {
var files = DriveApp.getFiles();
var file;
while (files.hasNext()) {
file = files.next();
Logger.log(file.getName() + ": " + file.getMimeType());
}
}

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()" />

Upload a file to google drive by an anonymous user

I use a Google Apps Script for that.
Code.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFile(form) {
var folderId = "folder_id";
try {
var folder = DriveApp.getFolderById(folderId);
var blob = form.picToLoad;
var file = folder.createFile(blob);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
Logger.log(error);
return error.toString();
}
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1 id="main-heading">Main Heading</h1>
<br/>
<div id="formDiv">
<form id="myForm">
<input name="picToLoad" type="file" /><br/>
<input type="button" value="Submit" onclick="picUploadJs(this.parentNode)" />
</form>
</div>
<div id="status" style="display: none">
Uploading. Please wait...
</div>
</body>
<script>
function picUploadJs(frmData) {
document.getElementById('status').style.display = 'inline';
google.script.run
.withSuccessHandler(updateOutput)
.uploadFile(frmData)
};
function updateOutput() {
var outputDiv = document.getElementById('status');
outputDiv.innerHTML = "The File was UPLOADED!";
}
</script>
</html>
It all works fine when I'm authenticated within my domain (I use G Suite).
However, if I'm logged into Google as another user (e.g. a normal Gmail user) or not logged at all, I still can access the page, but the script doesn't execute properly with the following error in the console:
Error
google.script.run.withSuccessHandler(...).processForm is not a function
at picUploadJs (VM84 userCodeAppPanel:9)
at HTMLInputElement.onclick (VM104 userCodeAppPanel:1)
No additional logs are shown in the Log at the level of Apps Script.
I have deployed the script as:
Execute the app as: Me (and authorised it)
Who can access the app: Anyone, even anonymous
So, I think all should work fine and anyone should be able to upload a file to my drive. Unfortunately that's not the case.
Again, this happens only when I access the script from outside of my domain.
Can anyone see what's wrong?
As it was suggested in the comments by Zig Mandel, making a copy of the script and running it solved the problem. This restarted the process of authorisation so perhaps there was something wrongly initiallised with the permissions.

HTMLService forms and responses

New to Google scripts. I cannot for the life of me get a Google script for forms working. The documentation is not helpful and I could not find any complete examples.
In sheets, I went to the script section. I created a basic "hello world" html. I added a function useMyForm, that will call on the script that has the form in it. After submit I cannot get the form to call the other script that has onFormSubmit.
Can someone write me a form with one entry and a call to the function that will process the data? Maybe my functions shouldn't be in separate scripts.
I write c, php, java..... this google script stuff is killing me.
Here is the sample code from the documentation, if there is something you don't understand please post your own version of the code that is not working:
https://developers.google.com/apps-script/guides/html/communication#forms
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
index.html
<script>
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
<form id="myForm">
<input name="myFile" type="file" />
<input type="button" value="Submit"
onclick="google.script.run
.withSuccessHandler(updateUrl)
.processForm(this.parentNode)" />
</form>
<div id="output"></div>
The one thing that took me a while to grasp is that when you run google.script.run.withSuccessHandler(updateUrl).processForm(this.parentNode)
.processForm(variable) will run a function in the .gs file.
The return from that function (in the .gs file) gets sent to the .withSuccessHandler(updateUrl) function. Which in the example above is the "url" variable from function updateUrl(url)