Send drive folder list to listbox HTML - google-apps-script

I have a script that is pulling all the folders in my drive. I want to push this data into a listbox that has been created in HTML (UiApp is deprecated)
The code I have is (note that the sheet.appendRow line doesn't work and if you know why and feel like explaining that would be awesome!!)
function updateFoldersListbox(FoldersListBox) {
var rootFolder = DriveApp.getRootFolder();
var driveFolders = rootFolder.getFolders();
while (driveFolders.hasNext()) {
var addMonitoredFolder = driveFolders.next();
Logger.log(addMonitoredFolder);
//sheet.appendRow(addMonitoredFolder);
}
The output of the logs is:
[15-09-26 01:38:46:603 BST] Test Folder
[15-09-26 01:38:46:605 BST] Untitled folder
[15-09-26 01:38:46:606 BST] Notes
Now to push that to a listbox and add test folder, untitled folder and notes as an option:
<select name="sometext" size="5">
<option>option1</option>
</select>
How is that done?

Put the following code in a script file:
function onOpen() {
SpreadsheetApp.getUi().createMenu('Dialog').addItem('Open', 'openDialog').addToUi();
};
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('Index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showModalDialog(html, 'Select a Google Drive Folder:');
};
function updateFoldersListbox() {
var rootFolder = DriveApp.getRootFolder();
var driveFolders = rootFolder.getFolders();
var listnames = new Array();
while (driveFolders.hasNext()) {
var addMonitoredFolder = driveFolders.next().getName();
listnames.push([addMonitoredFolder]);
//Logger.log(addMonitoredFolder);
//sheet.appendRow(addMonitoredFolder);
}
return listnames;
};
And put the following code in a HTML file 'Index.html':
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select id="menu"> </select>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(showThings)
.updateFoldersListbox();
google.script.run.withSuccessHandler(showMenu)
.updateFoldersListbox();
});
function showThings(things) {
var list = $('#things');
list.empty();
for (var i = 0; i < things.length; i++) {
list.append('<li>' + things[i] + '</li>');
}
}
function showMenu(menuItems) {
var list = $('#menu');
list.find('option').remove(); // remove existing contents
for (var i = 0; i < menuItems.length; i++) {
list.append('<option>' + menuItems[i] + '</option>');
}
}
</script>
</body>
</html>
Now, run the function 'openDialog' from the script editor.
Or refresh your spreadsheet and run the function from the custom menu 'Dialog' > 'Open'.

Related

Can I modify HtmlService Output using Google Apps Script?

I made an web app which copies folder and files of google drive. My goal is to show the name of the file and folder which is being copied on the web page('messages' id). Is it possible to change the web page from the google apps script?
When I open the web app, the GAS shows an output page using a form.html, and when I push the copy button, it will start start() function and begin copying the folders. After the successful process, the successHandler will call onSuccess() and it will change the innerHTML to Success.
I'd like to change the innerHTML during the copy process according to the folders' and files' name, but I don't know how to change it from the GAS function start() or copyFolder().
Thank you.
code.gs
function doGet(){
return HtmlService.createHtmlOutputFromFile('form');
}
function start() {
var sourceFolderId = "FOLDERID";
var targetFolder = "TARGET_FOLDER_NAME";
var source = DriveApp.getFolderById(sourceFolderId);
var target = DriveApp.createFolder(targetFolder);
copyFolder(source, target);
}
function copyFolder(source, target) {
var folders = source.getFolders();
var files = source.getFiles();
while(files.hasNext()) {
var file = files.next();
file.makeCopy(file.getName(), target);
}
while(folders.hasNext()) {
var subFolder = folders.next();
var folderName = subFolder.getName();
var targetFolder = target.createFolder(folderName);
copyFolder(subFolder, targetFolder);
}
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function callFolderDownload() {
document.getElementById('messages').innerHTML = 'Copying...';
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(onFailure)
.start();
}
function onSuccess() {
document.getElementById('messages').innerHTML = 'Success';
}
function onFailure(error)
{
document.getElementById('messages').innerHTML = error.message;
}
</script>
</head>
<body>
<div id="messages">Click the button to copy the folder.
</div>
<div>
<button type="button" onclick='callFolderDownload();' id="download">Copy</button>
</div>
</body>
</html>
You would need to break up your execution into various parts
You can't "stream" updates from the server process of copying a folder.
At the expense of making your execution slower, you can break it up into various phases, and at the end of each phase, update the client side with status. Remember that for every different stage you are having to:
- Make a call to Apps Script from client.
- Apps Script makes a separate call to Drive.
- Drive responds to Apps Script.
- Apps Script responds to client.
To get a message for each file copied, this needs to happen for each file. Depending on how many files you need to copy, this may not work. In that case, you would probably have to do it in batches. That is, maybe when you get the list of files back from the server, you can send 10 to the server to copy per request.
The key is that there has to be a separate call and response from server for each "real time update". These calls and responses need to be asynchronously programmed, that is, each stage needs to wait for previous stages to complete. This can result in the "pyramid of doom" which can be quite ugly and hard to understand:
google.script.run
.withSuccessHandler((targetId) => {
google.script.run
.withSuccessHandler((list) => {
newMessage("Starting to copy...");
list.forEach((item) => {
google.script.run
.withSuccessHandler(() => {
newMessage(item.name + " has been copied");
})
.copyItem(item.id, targetId);
});
})
.getFolderItems();
})
.createTargetFolder(targetName);
This can be made better with promises or the async await syntax, but in the interest of not making this answer too long, I have omitted it.
Below is an example of it working:
HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// This is a utility function to append a new message to the html
function newMessage(message) {
let messageElement = document.getElementById("messages")
let sourceDiv = document.createElement("div")
sourceDiv.innerText = message
messageElement.append(sourceDiv)
}
function copyFolder() {
newMessage("Preparing to copy...")
let targetName = document.getElementById("newFolderName").value
console.log(targetName)
google.script.run
.withSuccessHandler(targetId => {
google.script.run
.withSuccessHandler(list => {
newMessage("Starting to copy...")
list.forEach(item => {
google.script.run
.withSuccessHandler(() => {
newMessage(item.name + " has been copied")
})
.copyItem(item.id, targetId)
})
})
.getFolderItems()
})
.createTargetFolder(targetName)
}
</script>
</head>
<body>
<div>
<label for="newFolderName">Type in Name of new folder that contents will be copied to</label>
<input id="newFolderName" type="text">
<button type="button" onclick='copyFolder();' id="download">Copy</button>
</div>
<div id="messages">
-
</div>
</body>
</html>
Apps Script
class FileToCopy {
constructor(id, name) {
this.id = id;
this.name = name;
}
}
function doGet() {
return HtmlService.createHtmlOutputFromFile('form');
}
function createTargetFolder(name){
Logger.log(name)
var target = DriveApp.createFolder(name);
return target.getId()
}
function getFolderItems() {
var sourceFolderId = "[SOURCE_FOLDER_ID]";
var source = DriveApp.getFolderById(sourceFolderId);
var files = source.getFiles();
let output = []
while (files.hasNext()) {
var file = files.next();
let id = file.getId();
let name = file.getName();
let newItem = new FileToCopy(id,name)
output.push(newItem)
}
return output;
}
function copyItem(id, target) {
let file = DriveApp.getFileById(id)
let folder = DriveApp.getFolderById(target)
file.makeCopy(folder);
}
Result
Reference
Client to Server Communications

Google Drive Picker - Not showing all folders

I am using the Google Drive Picker API to facilitate file upload from within a Google Spreadsheet.
The problem the user is reporting is that not all folders in a sub folder are visible or searchable.
The sub folder in question has a large amount of sub folders itself. (About a 1000+)
Does anyone know if Drive Picker has some kind of a limitation around the number of folders it can display?
As requested my code below:
function showPicker() {
var html = HtmlService.createHtmlOutputFromFile('0.2 Picker.html')
.setWidth(600)
.setHeight(425)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showModalDialog(html, 'Select Invoice(s)');
}
function getOAuthToken() {
DriveApp.getRootFolder();
return ScriptApp.getOAuthToken();
}
//Picker.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script type="text/javascript">
var DIALOG_DIMENSIONS = {
width: 600,
height: 425
};
var pickerApiLoaded = false;
function onApiLoad() {
gapi.load('picker', {
'callback': function() {
pickerApiLoaded = true;
}
});
google.script.run.withSuccessHandler(createPicker)
.withFailureHandler(showError).getOAuthToken();
}
function createPicker(token) {
if (pickerApiLoaded && token) {
var docsView = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.spreadsheet')
.setParent("ID_OF_FOLDER_GOES_HERE");
var picker = new google.picker.PickerBuilder()
.addView(docsView)
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.enableFeature(google.picker.Feature.SUPPORT_DRIVES)
.hideTitleBar()
.setSize(DIALOG_DIMENSIONS.width - 2, DIALOG_DIMENSIONS.height - 2)
.setOAuthToken(token)
.setCallback(pickerCallback)
.setOrigin('https://docs.google.com')
.build();
picker.setVisible(true);
} else {
showError('Unable to load the file picker.');
}
}
/**
* A callback function that extracts the chosen document's metadata from the
* response object. For details on the response object, see
* https://developers.google.com/picker/docs/result
*
* #param {object} data The response object.
*/
function pickerCallback(data) {
//Get the user's response action
var action = data[google.picker.Response.ACTION];
//Test if users selected "Picked", if true, do the following:
if (action == google.picker.Action.PICKED) {
//Get documents uploaded by google picker
var files = data[google.picker.Response.DOCUMENTS];
//Create an array to house ID's of uploaded documents
var arrayOfIds = [];
//For the number of elements in the files array do the following
for (var i = 0; i < files.length; i++) {
//Get the id of the current file
var id = files[i][google.picker.Document.ID]
//Push id of current file into arrayOfIds
arrayOfIds.push(id)
}//END OF FOR LOOP I
//Call getInvoiceData passing in array of IDs
google.script.run.getInvoiceData(arrayOfIds);
//Close the upload box
google.script.host.close()
}//END OF IF STATEMENT
//Check action does not "Picked", check if action is "Cancel"
else if (action == google.picker.Action.CANCEL) {
google.script.host.close();
}//END OF ELSE IF
}//END OF FUNCTION
function showError(message) {
document.getElementById('result').innerHTML = 'Error: ' + message;
}
</script>
</head>
<body>
<div>
<p id='result'></p>
</div>
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>

Direct to a new page after form submission

Currently I've developed a Google Scripts API which is used for people to upload files to a shared Google Drive folder. After the file are uploaded successfully, I want them to be taken to a separate "Thank you" page so it is clear their upload has worked. Currently I only have a message on the same page to this effect and I cannot figure out how to direct to a new page that I have created.
This is the additional bit I found from different questions to try direct to a new page however this is not working so far, as it remains on the same upload form page. I have included it at the bottom of my code.gs file. Any ideas on how to direct to a custom page that just says "thank you" or something similar would be great!
function doPost(e) {
var template = HtmlService.createTemplateFromFile('Thanks.html');
return template.evaluate();
}
The rest of my code is as follows:
Code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('form').setSandboxMode(
HtmlService.SandboxMode.IFRAME);
}
function createFolder(parentFolderId, folderName) {
try {
var parentFolder = DriveApp.getFolderById(parentFolderId);
var folders = parentFolder.getFoldersByName(folderName);
var folder;
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = parentFolder.createFolder(folderName);
}
return {
'folderId' : folder.getId()
}
} catch (e) {
return {
'error' : e.toString()
}
}
}
function uploadFile(base64Data, fileName, folderId) {
try {
var splitBase = base64Data.split(','), type = splitBase[0].split(';')[0]
.replace('data:', '');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(fileName);
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFilesByName(fileName);
var file;
while (files.hasNext()) {
// delete existing files with the same name.
file = files.next();
folder.removeFile(file);
}
file = folder.createFile(ss);
return {
'folderId' : folderId,
'fileName' : file.getName()
};
} catch (e) {
return {
'error' : e.toString()
};
}
}
function doPost(e) {
var template = HtmlService.createTemplateFromFile('Thanks.html');
return template.evaluate();
}
Form.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div align="center">
<p><img src="https://drive.google.com/uc?export=download&id=0B1jx5BFambfiWDk1N1hoQnR5MGNELWRIM0YwZGVZNzRXcWZR"
height="140" width="400" ></p>
<div>
<form id="uploaderForm">
<label for="uploaderForm"> <b> Welcome to the Tesco's animal welfare and soy reporting system. </b> </label>
<BR>
<BR>
<div style="max-width:500px; word-wrap:break-word;">
Please add your contact information below and attach a copy of your company's animal welfare standard before clicking submit. Wait for the browser to confirm your submission and you may then close this page.
<BR>
<BR>
Thank you very much for your submission.
</div>
<BR>
<BR>
<div>
<input type="text" name="applicantName" id="applicantName"
placeholder="Your Name">
</div>
<BR>
<div>
<input type="text" name="applicantEmail" id="applicantEmail"
placeholder="Your Company">
</div>
<BR>
<BR>
<div>
<input type="file" name="filesToUpload" id="filesToUpload" multiple>
<input type="button" value="Submit" onclick="uploadFiles()">
</div>
</form>
<br>
<br>
<br>
<br>
<br>
<br>
<div id="output"></div>
<script>
var rootFolderId = '1-aYYuTczQzJpLQM3mEgOkWsibTak7KE_';
var numUploads = {};
numUploads.done = 0;
numUploads.total = 0;
// Upload the files into a folder in drive
// This is set to send them all to one folder (specificed in the .gs file)
function uploadFiles() {
var allFiles = document.getElementById('filesToUpload').files;
var applicantName = document.getElementById('applicantName').value;
if (!applicantName) {
window.alert('Missing applicant name!');
}
var applicantEmail = document.getElementById('applicantEmail').value;
if (!applicantEmail) {
window.alert('Missing applicant email!');
}
var folderName = applicantEmail;
if (allFiles.length == 0) {
window.alert('No file selected!');
} else {
numUploads.total = allFiles.length;
google.script.run.withSuccessHandler(function(r) {
// send files after the folder is created...
for (var i = 0; i < allFiles.length; i++) {
// Send each file at a time
uploadFile(allFiles[i], r.folderId);
}
}).createFolder(rootFolderId, folderName);
}
}
function uploadFile(file, folderId) {
var reader = new FileReader();
reader.onload = function(e) {
var content = reader.result;
document.getElementById('output').innerHTML = 'uploading '
+ file.name + '...';
//window.alert('uploading ' + file.name + '...');
google.script.run.withSuccessHandler(onFileUploaded)
.uploadFile(content, file.name, folderId);
}
reader.readAsDataURL(file);
}
function onFileUploaded(r) {
numUploads.done++;
document.getElementById('output').innerHTML = 'uploaded '
+ r.fileName + ' (' + numUploads.done + '/'
+ numUploads.total + ' files).';
if (numUploads.done == numUploads.total) {
document.getElementById('output').innerHTML = 'All of the '
+ numUploads.total + ' files are uploaded';
numUploads.done = 0;
}
}
</script>
<label for="uploaderForm">
Powered by 3Keel
</label>
</body>
</html>
Thanks.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Thank you for submitting!
</body>
</html>
EDIT:
I have changed this function as recommended:
if (numUploads.done == numUploads.total) {
window.location = 'Thanks.html';
numUploads.done = 0;
Now it is redirecting to another page but I am faced with this error:
That’s an error.
The requested URL was not found on this server. That’s all we know.
If you are looking for the solution of your issue yet, how about this answer?
You want to open Thanks.html when the process at Form.html is finished.
Form.html and Thanks.html are put in a project.
If my understanding is correct, how about this workaround? I have ever experienced with your situation. At that time, I could resolve this issue by this workaround.
Modification points:
It is not required to use doPost() to access to Thanks.html. I think that you can achieve what you want using doGet().
I think that #Scott Craig's answer can be also used for this situation. In my workaround, the URL of window.location = 'Thanks.html'; is modified.
Uses the URL of deployed Web Apps. In your script, when users access to your form, they access to the URL of the deployed Web Apps. In this workaround, it is used by adding a query parameter.
Modified scripts:
Form.html
For the script added in your question as "EDIT", please modify as follows.
From:
window.location = 'Thanks.html';
To:
window.location = 'https://script.google.com/macros/s/#####/exec?toThanks=true';
https://script.google.com/macros/s/#####/exec is the URL of the the deployed Web Apps. Please add a query parameter like toThanks=true. This is a sample query parameter.
Code.gs
Please modify doGet() as follows.
From:
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
To:
function doGet(e) {
if (e.parameter.toThanks) {
return HtmlService.createHtmlOutputFromFile('Thanks')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
} else {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
}
Note:
When the script of the deployed Web Apps was modified, please redeploy it as new version. By this, the latest script is reflected to Web Apps.
The flow of this modified script is as follows.
When users access to the Form.html, because the query parameter of toThanks=true is not used, Form.html is returned.
When onFileUploaded() is run and if (numUploads.done == numUploads.total) {} is true, it opens the Web Apps URL with the query parameter of toThanks=true. By this, if (e.parameter.toThanks) {} of doGet() is true, and Thanks.html is returned and opened it.
In my environment, I could confirm that this modified script worked. But if this didn't work in your environment, I'm sorry. At that time, I would like to think of about the issue.
I might be misunderstanding your question, but from what I understand, instead of this line:
document.getElementById('output').innerHTML = 'All of the '
+ numUploads.total + ' files are uploaded';
You want to redirect to Thanks.html. If that's correct, just replace the above line with:
window.location = 'Thanks.html';

Contents of a spreadsheet are not displayed in the deployed Apps Script webapp

I've tried to do an example of the 3rd tutorial on this ctrlq page, in which we display the content of a spreadsheet on a web page. Here are my files which I simply entered - I didn't activate anything, I just did Publish -> Deploy as web app
I expect to see all of the spreadsheet's values, but instead nothing is shown:
Code.gs
function doGet() {
var html = HtmlService.createTemplateFromFile("index").evaluate();
html.setTitle("Dynamic Webpage");
return html;
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.getContent();
}
function getData(){
var sheet = SpreadsheetApp.openById("1k_kj98U__0Bk44gh0qRFpaVx0ru3sN1pSPGiMQwimxo").getSheets()[0];
return sheet.getDataRange().getValues();
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<?!= include('script_js'); ?>
<body>
<div id="data"></div>
</body>
</html>
script_js.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
window.onload = function(){
google.script.run.withSuccessHandler(showData).getData();
}
function showData(data){
var html = "";
for (var i=0; i<data.length; i++) {
html += "<br>" + data[i].join(":");
}
document.getElementById("data").innerHTML = html;
}
</script>
</body>
</html>
Link to the script project
EDIT as #tehhowch pointed out his answer is the correct solution here.
For your case you should make these changes, getData():
function getData(){
var sheet = SpreadsheetApp.openById("1k_kj98U__0Bk44gh0qRFpaVx0ru3sN1pSPGiMQwimxo").getSheets()[0];
return JSON.stringify(sheet.getDataRange().getValues()); // return value as Json
}
And showData(data):
function showData(data) {
var arr = JSON.parse(data);
var html = "";
for (var i=0; i < arr.length; i++) {
html += "<br>" + arr[i].join(":");
}
document.getElementById("data").innerHTML = html;
}

Holding value in textarea for Google Script

I'm trying to write code that will help some of my users take a JSON response and convert it to a table in Google Sheets. I have the code for the JSON to Table script, courtesy of Amit Agarwal at www.ctrlq.org.
The way that I'm trying to do is that Google Sheets will generate a pop up for my user to copy and paste the JSON straight into it and then it will pass the object to the JSON to Table code. I'm having a problem figuring out how to actually do that.
Code.gs
function showPrompt()
{
var ui = SpreadsheetApp.getUi(); // Same variations.
var html = HtmlService.createHtmlOutputFromFile('Upload');
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Dialog title');
}
function setJSON(json)
{
var json = json; //json object?
return json;
}
// Written by Amit Agarwal www.ctrlq.org
function writeJSONtoSheet(json) {
var sheet = SpreadsheetApp.getActiveSheet()[1];
var keys = Object.keys(json).sort();
var last = sheet.getLastColumn();
var header = sheet.getRange(1, 1, 1, last).getValues()[0];
var newCols = [];
for (var k = 0; k < keys.length; k++) {
if (header.indexOf(keys[k]) === -1) {
newCols.push(keys[k]);
}
}
if (newCols.length > 0) {
sheet.insertColumnsAfter(last, newCols.length);
sheet.getRange(1, last + 1, 1, newCols.length).setValues([newCols]);
header = header.concat(newCols);
}
var row = [];
for (var h = 0; h < header.length; h++) {
row.push(header[h] in json ? json[header[h]] : "");
}
sheet.appendRow(row);
}
Dialog box HTML:
<!DOCTYPE html>
<html>
<head>
<script>
function setJSON() {
// how do i add value to set to set JSON
var json = ""
google.script.run.setJSON(json);
}
</script>
<base target="_top">
</head>
<body>
text text
<textarea rows="20" cols="20" placeholder="Paste your Data here. Do not format. Do not worry if it looks weird." name="json">DATA</textarea>
<input type="button" class="button" value="Submit JSON" onclick="setJSON()">
</body>
</html>
Thank you in advance!
Here's a simple example of triggering a dialog via an in-sheet menu and passing the input back to a server side function.
Code.gs
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Input Form Test')
.addItem('Input Form', 'showInputForm')
.addToUi();
}
function showInputForm() {
var html = HtmlService.createHtmlOutputFromFile('inputform');
SpreadsheetApp.getUi().showModalDialog(html, 'Input Form Test');
}
function logInput(input) {
Logger.log(input)
}
inputform.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
function setJSON(form) {
var jsonData = document.getElementById('json-data');
google.script.run.logInput(jsonData.value);
google.script.host.close();
}
</script>
<body>
<textarea id="json-data" rows="20" cols="20" placeholder="Paste your data here. Do not format. Do not worry if it looks weird." name="json">DATA</textarea>
<input type="button" class="button" value="Submit JSON" onclick="setJSON()">
</body>
</html>
Logging Output
After clicking the "Submit JSON" button with "test input" entered into the form, this is the output in the script logs:
[18-06-15 13:47:15:741 PDT] test input
Notes
I added an id attribute to the textarea element
the id is used to fetch the element programmatically
you may want to perform some client-side validations in setJSON(). For example:
verify that the value is not still the default value (i.e. DATA)
validate that the JSON data can be parsed succesfully (i.e. JSON.parse())
an example implementation with the above validations:
function setJSON(form) {
var jsonData = document.getElementById('json-data');
if (jsonData.value == 'DATA') {
alert("Please enter JSON data into the form.");
return;
}
try {
JSON.parse(jsonData.value)
}
catch(e) {
console.log(e); // Outputs to the browser console.
alert("Unable to parse JSON data.");
return;
}
google.script.run.logInput(jsonData.value);
google.script.host.close();
}
to fit your use case, in inputform.html you'd replace the logInput() call with either:
a function that calls JSON.parse() and then calls writeJSONtoSheet() with the result
writeJSONtoSheet() if you update it to expect text and add a JSON.parse() call at the beginning of the function