HTML Form does not submit to spreadsheet using doPost - javascript

tried to find some useful answer in existing threads but nothing is really matching my issue. I guess there is a quick fix to it, i just cannot see it.
I have a HTML form and want to upload the file to my google drive (works great) and save the text fields to my spreadsheet (does not work at all).
I just cannot find any major difference between the two functions, its frustrating!
Below my code, and here is also the [link to my public script][1].
Form:
<!DOCTYPE html>
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
<input type="submit" value="Upload File"
onclick="this.value='Uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;
google.script.run.withSuccessHandler(fileUploaded)
.doPost(this.parentNode);">
</form>
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
[1]: https://script.google.com/d/1K9jGl7ALHCZ93rz8GoeV8t7PE_7vgbNZlLJed1h6ZWyuoon11gIbik24/edit?usp=sharing
server.gs:
function doGet(e) {
var html = HtmlService.createTemplateFromFile("form");
html = html.evaluate();
html.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}
function uploadFiles(form) {
try {
var dropbox = "Customer Shapes";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
function doPost(form) { // change to doPost(e) if you are recieving POST data
html.setSandboxMode(HtmlService.SandboxMode.EMULATED);
var name = form.myName;
var url="url...";
var message = 'Ram';
var submitSSKey = '...kHI';
var sheet = SpreadsheetApp.openById(submitSSKey).getActiveSheet();
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1, 1, 2, 2).setValues([[name,url]]);
}
Thank You for Your kind help!
Martin

If you are going to use google.script.run, then it's pointless to have a function named doPost(). And it's also pointless to have a submit type input tag: type="submit"
If you want to run a withSuccessHandler(fileUploaded) to change the display, you can't have a button inside of the form. It will cause the display to go blank.
And you don't need two google.script.run calls. You need multiple changes and improvements:
form.html
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
</form>
<input type="button" value="Upload File"
onclick="this.value='Uploading..';
var theForm = document.getElementById('myForm');
google.script.run.withSuccessHandler(fileUploaded)
.processFormData(theForm);">
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
server.gs
function processFormData(form) {
uploadFiles(form.myFile);//Call first function to process the file
var innerArray = [];
var outerArray = [];
innerArray.push(form.myName);
innerArray.push(form.myFile);
outerArray.push(innerArray);//Call second function to write data to SS
writeDataToSS(outerArray);
};
function uploadFiles(theFile) {
try {
var dropbox = "Customer Shapes";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = theFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + theFile);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
function writeDataToSS(values) {
//html.setSandboxMode(HtmlService.SandboxMode.EMULATED);
var url="url...";
var message = 'Ram';
var submitSSKey = '...kHI';
var sheet = SpreadsheetApp.openById(submitSSKey).getActiveSheet();
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1, 1, 1, 2).setValues(values);
}
The html file is not a template, it does not have a scriptlet in it. Just use createHtmlOutputFromFile():
function doGet(e) {
var html = HtmlService.createHtmlOutputFromFile("form");
html.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}

Related

Parse file only one time using papaParse

I want to create a web app to make simple actions on a csv. For example, the user would upload a csv file then all columns would show up on a form, the user could select some columns to remove them from the file and finally the user could download the modified file.
I have already done something working but there is definitely room for improvement. The most important one is that in my current solution I have to parse the file two times because Papaparse is asynchronous, one time to get the columns and another time to remove columns from the user input.
Is there a way to parse the file only one time and then use the resulting object through the rest of the code ?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSV Manipulator</title>
<link rel="stylesheet" href="style.css" />
</head>
<script src="script.js"></script>
<script src="papaparse/papaparse.min.js"></script>
<body>
<div id="csv_columns">
<label for="file">choose csv file</label>
<input id="input-file" autocomplete="off" type="file" id="file" name="file">
<input type="button" value="download CSV" onclick="downloadCSV()">
</div>
<div id="schema_select">
<form action="#">
<label for="schema">Schema</label>
<select name="schema" id="schema" multiple>
</select>
<button id="submit-option">Submit</button>
</form>
<input type="text" , autocomplete="off" name="csv-file-name" id="csv-file-name">
</div>
</body>
</html>
window.onload = function () {
inputElement = document.getElementById("input-file")
inputElement.onchange = function (event) {
var fileList = inputElement.files;
parseDatatoGetSchema(fileList[0])
}
var newCsvFileName = document.getElementById("csv-file-name").value
var submitOption = document.getElementById("submit-option");
submitOption.addEventListener("click", function (event) {
var columnsToRemove = handleSubmit(event)
console.log(columnsToRemove)
parseDataRemoveColumns(inputElement.files[0], columnsToRemove, newCsvFileName)
});
}
function removeColumns(parsedCsv, columnsToRemove) {
newParsedCsv = []
for (i = 0; i < parsedCsv.data.length; i++) {
newObj = {}
for (key in parsedCsv.data[i]) {
if (!(columnsToRemove.includes(key))) {
newObj[key] = parsedCsv.data[i][key]
}
}
newParsedCsv.push(newObj)
}
return newParsedCsv
}
function showCsvSchema(results) {
//Data is usable here
var schemaForm = document.getElementById("schema")
// ajoute le nœud texte au nouveau div créé
for (i = 0; i < Object.keys(results.data[0]).length; i++) {
var opt = document.createElement('option');
opt.value = Object.keys(results.data[0])[i];
opt.innerHTML = Object.keys(results.data[0])[i];
schemaForm.appendChild(opt);
}
}
function handleSubmit(event) {
event.preventDefault();
var schemaSelect = document.getElementById("schema")
columnsToRemove = [...schemaSelect.selectedOptions].map(o => o.value)
return columnsToRemove
}
function parseDatatoGetSchema(url) {
csvData = []
Papa.parse(url, {
header: true,
dynamicTyping: true,
complete: function (results) {
showCsvSchema(results)
}
});
}
function parseDataRemoveColumns(url, columnsToRemove, newCsvFileName) {
csvData = []
Papa.parse(url, {
header: true,
dynamicTyping: true,
complete: function (results) {
newParsedCsv = removeColumns(results, columnsToRemove)
unParsedNewCsv = Papa.unparse(newParsedCsv)
downloadCSV(unParsedNewCsv, newCsvFileName)
}
});
}
function downloadCSV(unparse_csv, newCsvFileName) {
var csvData = new Blob([unparse_csv], { type: 'text/csv;charset=utf-8;' });
var csvURL = null;
if (navigator.msSaveBlob) {
csvURL = navigator.msSaveBlob(csvData, `${newCsvFileName}.csv`);
}
else {
csvURL = window.URL.createObjectURL(csvData);
}
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', `${newCsvFileName}.csv`);
tempLink.click();
location.reload()
}

Newline Break when saving innerHTML to text file I automatically get a newline Break in the saved Text file or when reload the page

The result in the text file is always saving the file with a linebreak not just the p tag in div1 when clicking the button.
example:
<p>x1</p>
....linebreak
If I click the button 3 time and reload the page and click the button again I get this as well.
<p>x1</p><p>x2</p><p>x3</p>
<p>x1</p>
html code:
<button id="btn" value="" onclick="btn();return false"style="margin:1px"> Write to file </button>
<div id="div1" style="width:200px; border:1px; margin:5px 0px;"></div>
Javascript code:
// Read or Write to file
var path = 'c:\\home\\lab.txt';
var num = 0 ;
var myDiv = document.getElementById('div1');
// Read or Write to file
var path = 'c:\\home\\lab.txt';
var num = 0 ;
var myDiv = document.getElementById('div1');
myDiv.innerHTML = readFileInIE(path);
function readFileInIE(path) {//Read file content
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath, 1);
var rfileContent = file.ReadAll();
file.Close();
return rfileContent;
} catch (err) {
alert('Unable to access local files or location. '+ err);
return "";
//}
}
function btn(){ //onClick Calls writeFileInIE and paragraph to file on new line.
num++;
var myInput= "P" + num.toString();
var myPara = '<p>' + myInput + '</p>';
myDiv.innerHTML = myDiv.innerHTML + MyPara;
writeFileInIE(path, myDiv.innerHTML);
}
function writeFileInIE(filePath, fileContent) { //Write to file function
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath, 2, true);
file.WriteLine(fileContent);
file.Close();
return fileContent;
} catch (err) {
alert('Unable to access local files or location.');
file.Close();
}
}
My goal is to be able to write to the file only the innerHTML from the div1 element innerHTML to the text only content in this format.
example in exact format I want even on a reload to the text file :
<p>x1</p>
<p>x2</p>
<p>x3</p>
<p>x1</p>
<p>x2</p>
Can't test your code but i see you comment and ending } , probably that is messing with your code.
//} after the return you should uncomment
function readFileInIE(path) {//Read file content
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath, 1);
var rfileContent = file.ReadAll();
file.Close();
return rfileContent;
} catch (err) {
alert('Unable to access local files or location. '+ err);
return "";
//}
}
After that, try put a <br> maybe it will do that break you want
var myPara = '<p>' + myInput + '</p><br/>';
Ok many be with this you will see what I mean by not getting the correct format and it keeps adding a line break to the file c:\lab.txt. It works fine the with the button.
Until I reload the page or refresh it I get a newline Break so I end up with this
<p>P1</p>
<p>P2</p>
<p>P1</p>
<p>P1</p>
<p>P2</p>
<p>P3</p>
I want it to do this:
<p>P1</p>
<p>P2</p>
<p>P1</p>
<p>P3</p>
<p>P1</p>
<p>P2</p>
<p>P3</p>
I want it to allways save the file with out blank line breaks between the P tags.
It fine if I star with a blank document but once it reloads with data in the text file.
I will get a new linebreak saves in the middle.
Try to use the new code I have posted.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Page OPEN</title>
<Script language="JavaScript">//*/alert("helloWorld".toUpperCase())
</Script>
</head>
<body>
<h5> "Lab.txt file populating div1.innerHTML that is being changed via JavaScript while being save to Lab.txt"</h5>
<div id="div1" style="width:600px; height:150px; border:1px dotted; margin:5px 0px; overflow: scroll;"></div>
<table>
</tr>
<tr>
<td><button id="btn1" value="" onclick="btnWrite();return false"> Write to file </button></td>
<td><button id="btn2" value="" onclick="btnRead() ;return false"> Read from file</button></td>
</tr>
<tr>
<td>Content Sent to file</td>
<td>File Content</td>
</tr>
<tr><td><pre id="pre1" style='border:1px solid red ; width:300px; height: 300px; overflow: scroll;'></pre>1</td>
<td><pre id="pre2" style='border:1px solid blue; width:300px; height: 300px; overflow: scroll;'></pre>2</td>
</table>
<div id="lastDiv"></div>
<Script language="JavaScript">//*/alert("helloWorld".toUpperCase())
var lDiv = document.getElementById('lastDiv')
// Read or Write to file
var path = 'c:\\home\\lab.txt'; // Change to any location will create the file.
var num = 0 ;
var myDiv = document.getElementById('div1');
myDiv.innerHTML = readFileInIE(path);
function btnRead(){ //onClick Calls writeFileInIE and paragraph to file on new line.
document.getElementById('pre2').innerText = readFileInIE(path);
//document.getElementById("pre2").innerText = "hello";
}
function readFileInIE(readPath) {//Read file content
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(readPath, 1);
var readFileContent = file.ReadAll();
file.Close();
return readFileContent;
} catch (err) {
tkr("Error on reading: "+ path + " - " + err);//alert('Unable to access local files or location. '+ err);
return "";
}
}
function btnWrite(){ //onClick Calls writeFileInIE and paragraph to file on new line.
num++;
var myCode =""
var myInput= "P" + num.toString();
var myPara = '<p>' + myInput + '</p>'+'\n';
myDiv.innerHTML = myDiv.innerHTML + myPara;
document.getElementById('pre1').innerText = writeFileInIE(path, myDiv.innerHTML);
document.getElementById('pre2').innerText = readFileInIE(path);
}
function writeFileInIE(filePath, wFileContent) { //Write to file function
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath, 2, true);
file.WriteLine(wFileContent);
file.Close();
return wFileContent;
} catch (err) {
tkr("Error on write file: "+ path + " - "+ err);//alert('Unable to access local files or location.');
file.Close();
return err;
}
}
//*/
// track locations and find errors debug
function tkr(myData){lDiv.innerHTML = lDiv.innerHTML + "<p>" + myData + "</p>";}
tkr("JavaScript complete onload");
</Script>
</body>
</html>

Pass a variable from web app and display dialog

I am trying to pass a searchterm from a google web app to display the results. I am having trouble on submission I receive a blank screen. When the form is submitted, I would like it to display the results. The main code works within the logger- now I am just working on the UI and getting the form to work.
Any help is appreciated!
So far this is the code I have:
CODE:
function SearchFiles() {
//Please enter your search term in the place of Letter
var searchterm ="'mysearchinput'"; \\ this would be the variable that is passed from the form on index.html
var searchFor ="title contains " + searchterm;
var owneris ="and 'youremail#yourdomain.com' in Owners";
var names =[];
var fileIds=[];
var files = DriveApp.searchFiles(searchFor + owneris);
while (files.hasNext()) {
var file = files.next();
var fileId = file.getId();// To get FileId of the file
fileIds.push(fileId);
var name = file.getName();
names.push(name);
}
for (var i=0;i<names.length;i++){
Logger.log(names[i]);
Logger.log("https://drive.google.com/uc?export=download&id=" + fileIds[i]);
}
}
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function processForm(formObject) {
Logger.log('I was called!');
// here is where I would like to display results of searthterm.
}
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function onFailure(error) {
var div = document.getElementById('output');
div.innerHTML = "ERROR: " + error.message;
}
</script>
</head>
<body>
Hello, World!
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input type="text" name="search">
<input type="submit" value="Submit" />
</form>
<input type="button" value="Close"
onclick="google.script.host.close()" />
SEARCH FUNCTION:
function SearchFiles() {
Logger.log('I Searched Files');
//Please enter your search term in the place of Letter
var searchterm ="'Whatevertextisinthesearchbox'";
var searchFor ="title contains " + searchterm;
var owneris ="and 'Youremail#yourdomain' in Owners";
var names =[];
var fileIds=[];
var files = DriveApp.searchFiles(searchFor + owneris);
while (files.hasNext()) {
var file = files.next();
var fileId = file.getId();// To get FileId of the file
fileIds.push(fileId);
var name = file.getName();
names.push(name);
}
for (var i=0;i<names.length;i++){
// Logger.log(names[i]);
// Logger.log("https://drive.google.com/uc?export=download&id=" + fileIds[i]);
var filesreturned = {
name:names[i],
urls:"https://drive.google.com/uc?export=download&id=" + fileIds[i]
}
Logger.log(filesreturned.name + " - " + filesreturned.urls);
return(filesreturned);
}
}
As per your comment above, here is the code to simply show hello world on button click. For your reference, I have also added a code to pass data between javascript and appscript.
Index.html file
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function displayMessage()
{
google.script.run.withSuccessHandler(helloWorld).parseDataFromAppscript();
}
function helloWorld(stringText)
{
document.writeln(stringText);
}
</script>
</head>
<body>
<input type="button" value="submitButton" name="submitButton" onclick="displayMessage()"/>
</body>
</html>
Code.gs file
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index');
return template.evaluate()
.setTitle('Hello World')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function parseDataFromAppscript()
{
return "Hello World!";
}
To run this, go to publish -> deploy as web app -> update. And then click latest code.
If you want explanation for any part, please feel free to ask. I'm assuming you already know html javascript and google.script.run method. :)

Printing output of multiple html files in Javascript

I am trying to print the text multiple files in html. I succeeded in printing the single file. But I am unable to print the text output of a multiple files. Can you please help me in correcting the code?`
<!DOCTYPE html>
<html>
<body>
<h1> Testing programs </h1>
<input type="file" id="fileinput" multiple />
<pre id="file-content"></pre>
<h3>Contents of the file:</h3>
<script type="text/javascript">
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (!files) {
for (var i=0, f; f=files[i]; i++) {
var r = new FileReader();
r.onload = (function(f) {
return function(e) {
var contents = e.target.result;
displayContents(contents);
};
});
r.readAsText(f);
}
} else {
alert("Failed to load files");
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML = contents;
}
document.getElementById('fileinput').addEventListener('change', readMultipleFiles, false)
</script>
</body>
</html>`
There is no need to use closure in provided snippet. As suggested by gurvinder, use innerHTML +=
if condition should be like if (files) as it will be true if length of files is greater than 0
Try this:
function readMultipleFiles(evt) {
var files = evt.target.files;
if (files) {
for (var i = 0; i < files.length; i++) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
};
r.readAsText(files[i]);
}
} else {
alert("Failed to load files");
}
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML += contents;
}
document.getElementById('fileinput').addEventListener('change', readMultipleFiles, false);
<h1> Testing programs </h1>
<input type="file" id="fileinput" multiple />
<pre id="file-content"></pre>
<h3>Contents of the file:</h3>
Also refer this fiddle : https://jsfiddle.net/rayon_1990/2cwr4c00/
just replace the displayContents method as
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML += contents; //observe + before =
}
since it needs to append the files rather than replace the last one

Upload file with google apps script using html service

I want to upload a file using the HtmlService of GAS but it doesn't work.
I found informations in this topic Uploading file using Google Apps Script using HtmlService but it doesn't fit with my issue.
Here is an example that describes my problem:
Code.gs:
function doGet() {
return HtmlService.createTemplateFromFile("index").evaluate();
}
//For some reasons, this function has to be in code.gs
funcion getHTML() {
var html = "<form id='myform'>"+
"<input name='myfile'>"+
"</form>"+
"<div data-formname='myform'> Submit form </div>";
return html;
}
function uploadFile(file) {
DriveApp.createFile(file); *//Doesn't work :/*
}
Javascript:
$(document).on("click","div", function(e) {
var idform = $(this).data("formname");
if (idform)
sendForm(idform);
});
function trigger() {
google.script.run.withsuccesshandler(setHTML).getHTML();
}
function setHTML(html) {
$("#myHTML").html(html);
}
function sendForm(idForm) {
var formElements = document.getElementById("idForm").elements;
var form = {};
for (var key in formElements) form[key] = formElements[key];
google.script.run.withsuccesshandler().uploadFile(form["myfile"]);
}
index.html
<body onload="trigger()">
<div id='myHTML'></div>
</body>
Your code seems a bit overcomplicated... try this simple code
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function serverFunc(theForm) {
var fileBlob = theForm.theFile; // This is a Blob.
var adoc = DocsList.createFile(fileBlob);
return adoc.getUrl();
}
index.html
<div>
<script>
function cliHandler(e){
document.getElementById('button').value = "Document is downloadable at url "+e
}
</script>
<form>
<input type="file" name="theFile">
<input type="button" value="UpLoad" id="button" onclick="google.script.run.withSuccessHandler(cliHandler).serverFunc(this.parentNode)">
</form>
</div>

Categories

Resources