How to call server-script function on HTML Service button click - google-apps-script

I have a library and have imported into my spreadsheet.
Library file contains these 2 files (sona)
customHtml.gs // UI
customScript.gs // Code
Spreadsheet file
code.gs
In customHtml.gs code (my library)
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> </script>
<input id="txt1" type="text" />
<input id="txt2" type="text" />
<input id="Button1" class="btnSave" type="button" value="Save" />
<script>
$("#Button1").on('click',function(){
var param1=$("#txt1").val();
var param2=$("#txt2").val();
google.script.run.getCars(param1, param2);
});
</script>
customScript.gs
function sonatask_Assign(){
var html = HtmlService.createHtmlOutputFromFile('customHtml')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(900)
.setHeight(500);
return html;
}
function getCars(param1, param2){
// code logic
Logger.log(param1,param2);
}
Spreadsheet (code.gs)
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('► BOT')
.addSeparator()
.addItem('Task Assign ', 'fn_task_Assign')
.addItem('☎ Help ', 'helpMethod')
.addToUi();
}
// display dialog box with custom HTML (which is stored in library)
function fn_task_Assign(){
// get html from library (reason behind using HTML from library, is to acces only specific user. As spreadsheet is availabe to all any one can make a copy of it, but functions will not work unless i acces them to this library )
var showHTML = sona.sonatask_Assign();
Logger.log(abc);
SpreadsheetApp.getUi().showModalDialog(showHTML, " ");
}
On fn_task_Assign it display modelbox. i.e. 2 txtbox and a button.
Now on button click I try to call getCars function, but its not working.

Create getCars inside your code.gs and call sona.getCars();
function getCars(param1, param2) {
sona.getCars(param1, param2);
}
Also in oder this all to work, your library needs tobe a Stand alone script. Otherwise it wont work.

Related

How to upload file from local to Drive using HTML service dialog in apps script?

Attempting to upload a file to google drive from Local using a custom HTML dialog.
On clicking upload in the dialog it waits a few seconds and then shows an error:
"failed UploadWe're sorry, a server error occurred. Please wait a bit and try again."
It is just not running the server side function. I have tried changing the server side function just to return anything and it is just not working so I don't think it's a problem with the server side function itself. Something about the communication between client and server.
Do you have any idea why this is not working?
// Use this code for Google Docs, Slides, Forms, or Sheets.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.createMenu('Dialog')
.addItem('Upload', 'uploadDialog')
.addToUi();
}
function uploadDialog() {
var html = HtmlService.createHtmlOutputFromFile('Index');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Upload File Here');
}
function uploadFile(frmdata) {
var fileBlob = frmdata.fileToUpload
if (fileBlob.getName() != "") {
var fldrSssn = DriveApp.getFolderById("1nFl9S3pgR9IXSKVuKh9sUGOKi5adEHR1");
var picFile = fldrSssn.createFile(fileBlob);
}
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form id="fileform" onsubmit="event.preventDefault()">
<input type="file" id="file" name="fileToUpload">
<input type="Button" value="Upload" onclick="uploadthis(this.parentNode)">
</form>
</body>
<script>
function uploadthis(frmData) {
google.script.run
.withSuccessHandler(closeDialog)
.withFailureHandler(alertFailure)
.uploadFile(frmData);
}
function closeDialog() {
google.script.host.close()
}
function alertFailure(error) {
google.script.host.close()
alert("failed Upload" + error.message)
}
</script>
</html>
This behavior is a known issue with V8 runtime. Here is the link: https://issuetracker.google.com/150675170. You can click on the star icon to indicate you are affected by it too.

How to pass file upload blob from HTML form to server-side Apps Script?

The Google support article example under the Forms heading is broken. From the article:
If you call a server function with a form element as a parameter, the form becomes a single object with field names as keys and field values as values. The values are all converted to strings, except for the contents of file-input fields, which become Blob objects.
I tested this by passing a Form element containing 5 text inputs and a file, then logging Object.keys() on the form object. It returned only the 5 text fields, the file was stripped from the form object. Attempting to assign the file blob directly returned Exception: Invalid argument: blob
How do I pass the file blob from the client-side Form to the server-side Apps Script?
EDIT: To clarify, I also copy-pasted the example provided by Google verbatim. It errors with Exception: Invalid argument: blob.
To reproduce:
Create new Google Apps Script project
Index.html contents:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<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);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>
Code.gs contents:
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
Publish as Web App
Submit the form with any file
Observe error in View -> Stackdriver Logging -> Apps Script Dashboard
Here's an example:
html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
function fileUploadJs(frmData) {
document.getElementById('status').style.display ='inline';
google.script.run
.withSuccessHandler(updateOutput)
.uploadTheFile(frmData)
}
function updateOutput(info) {
var br='<br />';
var outputDiv = document.getElementById('status');
outputDiv.innerHTML = br + 'File Upload Successful.' + br + 'File Name: ' + info.name + br + 'Content Type: ' + info.type + br + 'Folder Name: ' + info.folder;
}
console.log('My Code');
</script>
<style>
body {background-color:#ffffff;}
input{padding:2px;margin:2px;}
</style>
</head>
<body>
<h1 id="main-heading">Walking Tracks</h1>
<h3>Upload GPS Tracks Files</h3>
<div id="formDiv">
<form id="myForm">
<input name="fileToLoad" type="file" /><br/>
<input type="button" value="Submit" onclick="fileUploadJs(this.parentNode)" />
</form>
</div>
<div id="status" style="display: none">
<!-- div will be filled with innerHTML after form submission. -->
Uploading. Please wait...
</div>
<div id="controls">
<input type="button" value="Close" onClick="google.script.host.close();" />
</div>
</body>
</html>
server code:
function uploadTheFile(theForm) {
var fileBlob=theForm.fileToLoad;
var fldr = DriveApp.getFolderById('FolderId');
var file=fldr.createFile(fileBlob);
var fi=formatFileName(file);
var fileInfo={'name':fi.getName(),'type':fileBlob.getContentType(), 'size':fileBlob.getBytes(), 'folder':fldr.getName()};
return fileInfo;
}
I can confirm that this doesn't work in G-Suite Enterprise. I don't know why because I cannot find documentation that says how Google is serializing the data. It could be a browser/computer security setting or something in G-Suite.
However, there is an easier way to accomplish your need. You can use a Google Form with a file upload question and then create an on form submit trigger/event on it to copy the file to a team/shared drive. Here is sample code if you want to attach the trigger to the Google Form itself:
// ID of the destnation folder to save the file in
var destinationFolderID = "10gkU_2V9iYy-VKudOCOjydEpoepPTgPv"
function saveFileToTeamDrive(e)
{
// a place to save the URL of the uploaded file
var fileID;
// go through all of the responses to find the URL of the uploaded file
e.response.getItemResponses().forEach(function(itemResponse){
// once we find the question with the file
if(itemResponse.getItem().getTitle() == "File Upload Test")
{
// get the file ID from the response
fileID = itemResponse.getResponse();
return;
}
});
// stop if we didn't have one
if(!fileID.length) return;
// get the first index in the array
fileID = fileID[0];
// get the file
var file = DriveApp.getFileById(fileID);
// get the destination folder
var destinationFolder = DriveApp.getFolderById(destinationFolderID);
// make a copy
var newFile = file.makeCopy(destinationFolder);
Logger.log(newFile.getUrl());
}
You can also attach to the on form submit event of a Google Sheet that is linked to a Google Form. I find that way easier cause the Google Sheet on form submit trigger/event includes a JSON of the question/answers so you don't have to iterate all of them to find it. It also means you can re-run a submission if it failed.
WARNING
One important note, if you do either of these things do not give anyone else edit access to the code. This is because as soon as you create and authorize the trigger, anyone who has edit access to the code would be able to use it to gain access to your Google Drive (and anything else the trigger is authorized for). Please see securing a Google Apps Script linked to an authorized trigger so others can edit for more information.

Google Script: ui.prompt, submit by pressing enter instead of click button

How can i submit a ui.prompt in Google Script bypressing "enter key" instead of clicking ok?
Code so far:
function PromptBox()
{
var spreadsheet = SpreadsheetApp.getActive();
var ui=SpreadsheetApp.getUi();
var prompt=ui.prompt("Filter op... ", "Geef je filterwoord op", ui.ButtonSet.OK)
var response=prompt.getResponseText();
var button=prompt.getSelectedButton();
var filterTekst = "";
if (button==ui.Button.OK)
{
return (filterTekst = response);
}
else if(button==ui.Button.CANCEL)
{
ui.alert("Je hebt geannuleerd");
}
}
Roll your own dialog/prompt
You can accomplish this by rolling your own dialog. This a templated html approach so you will have to create some files to implement it. It isn't necessary to do it this way. It happens to be easier for me because all of the css, resource and script files were already created and I find it easier to create the javascript in a file rather than in a string.
Google Script Code:
function showPromptResponse(title,prompt,placeholder){
var title=title || "Prompt Response";//default used for debug
var prompt=prompt || "Enter your Response";//default used for debug
var placeholder=placeholder || "This is the placeholder";//default used for debug
var html="";
html+='<!DOCTYPE html><html><head><base target="_top"><?!= include("res1") ?><?!= include("css1") ?></head><body>';
//html+='<body>';
html+=Utilities.formatString('<h1>%s</h1>', title);
html+=Utilities.formatString('<p>%s</p>',prompt);
html+=Utilities.formatString('<br /><input id="resptext" type="text" size="25" placeholder="%s" />',placeholder);
html+='<br /><input id="okbtn" type="button" value="Ok" onClick="getResponse();" />';
html+='<br /><input id="cancelbtn" type="button" value="Cancel" onClick="google.script.host.close();" />';
html+='<?!= include("promptscript") ?>';
html+='</body></html>';
var ui=HtmlService.createTemplate(html).evaluate();//This is a template
SpreadsheetApp.getUi().showModelessDialog(ui, 'My Prompt');//launch dialog here
}
function loadResponse(resptext) {//This function determines where response is loaded into the spreadsheet.
SpreadsheetApp.getActive().getActiveSheet().getRange('A1').setValue(resptext);
}
function include(filename){//used in the template for loading file content
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
Javascript in a file named promtscript.html
<script>
$(function(){
var input = document.getElementById("resptext");
input.addEventListener("keyup", function(event) {
event.preventDefault();//this isn't required since were not doing a submit but it doesn't seem to hurt anything so I left it.
if (event.keyCode === 13) {//this captures the return keypress
document.getElementById("okbtn").click();
}
});
});
function getResponse(){
var responseText=$('#resptext').val();
console.log(responseText);
if(responseText){
google.script.run.loadResponse(responseText);//send response to google script
}else{
alert('Invalid or No Response');//response if nothing entered
}
}
</script>
The res1.html file is this:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
The css1.html file is this:
<style>
body {background-color:#ffffff;}
input{padding:2px;margin:2px;}
</style>
Templated HTML
Client To Server Communication

Apps Script dialog box - HTML Service - Apply "withSuccessHandler" Properly - google.script.run

Background
I'm fairly new to coding in general and as I've gone through building this little UI for Google Sheets using GAS, this is one of the concepts that has just has me stumped. I've tried and tried reading, understand conceptually and apply withSuccessHandler(function) to all sorts of examples but I just can't seem to get it to work.
Here's what I understand so far:
When you run the following on the client side (e.g. Index.html):
google.script.run.withFailureHandler(CallbackFunction).ServerSideFunction(aVariable)
a. ServerSideFunction(aVariable): This function from your Code.gs is first called and returns a value, "OutputA," back to Index.html.
b. CallbackFunction: Then, this function is called and uses "OutputA" as its input and returns another value which you can use for whatever purpose.
Goal
Open Dialog Box asking for "Name" and "E-mail." DONE
Once user hits "Submit" the input is populated in the spreadsheet. DONE
The form is then cleared so they can potentially add another person or exit if they want.
Question
For that last piece, I can't seem to get withSuccessHandler to return a value back from my script, confirming that the inputs were entered properly, and I really don't know how to proceed.
I've included a working version of the code below without withSuccessHandler for reference. Any help at all in better understanding this and how I can incorporate it into the code below would be greatly appreciated!
Google Script
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu('Menu')
.addItem('Add Member', 'createDialog')
.addToUi();
}
function createDialog() {
var htmlOutput = HtmlService
.createHtmlOutputFromFile('Index')
.setWidth(300)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, " ");
}
function addAName(bName, bEmail) {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var ControlSheet = sheet.getSheetByName('Control Sheet');
var lRow = ControlSheet.getRange(1, 1, ControlSheet.getLastRow(), 1).getValues().filter(String).length;
var Name = ControlSheet.getRange(lRow + 1, 1);
var Email = ControlSheet.getRange(lRow + 1, 2);
var ValidName = /(^[A-Za-z]+)\s([A-Za-z]{1}[.]{1}\s)?([A-Za-z]+$)/g;
var ValidEmail = /(^[A-Za-z]+)([.]{1})([A-Za-z]{1}[.]{1})?([A-Za-z]+)(#google.com|#yahoo.com)$/g;
if (bName.match(ValidName) && bEmail.match(ValidEmail)) {
Name.setValue(bName);
Email.setValue(bEmail);
}
}
HTML
<body>
<h2>Add New Member</h2>
<div class="mdc-layout-grid">
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-12">
<div class="mdc-text-field mdc-text-field--upgraded" data-mdc-auto-init="MDCTextField">
<input class="mdc-text-field__input" id="Name" type="text" aria-controls="name-validation-message" pattern="(^[A-Za-z]+)\s([A-Za-z]{1}[.]{1}\s)?([A-Za-z]+$)">
<label for="Name" class="mdc-floating-label">Name</label>
<div class="mdc-line-ripple"></div>
</div>
<p class="mdc-text-field-helper-text mdc-text-field-helper-text--validation-msg" id="name-validation-message" aria-hidden="true">
Please enter your full name.
</p>
</div>
<div class="mdc-layout-grid__cell mdc-layout-grid__cell--span-12">
<div class="mdc-text-field" data-mdc-auto-init="MDCTextField">
<input class="mdc-text-field__input" id="Email" type="text" aria-controls="name-validation-message" pattern="(^[A-Za-z]+)([.]{1})([A-Za-z]{1}[.]{1})?([A-Za-z]+)(#google.com|#yahoo.com)$">
<label for="Email" class="mdc-floating-label">Email Address</label>
<div class="mdc-line-ripple"></div>
</div>
<p class="mdc-text-field-helper-text mdc-text-field-helper-text--validation-msg" id="name-validation-message" aria-hidden="true">
Please enter a valid Google or Yahoo email address.
</p>
</div>
</div>
<div class="Right_Side">
<button class="mdc-button mdc-button--unelevated secondary-filled-button" OnClick="google.script.host.close()">Cancel
</button>
<button class="mdc-button mdc-button--unelevated primary-filled-button" OnClick="sendInputToGS()">Submit
</button>
</div>
<script>
window.sendInputToGS = function() {
var aName = document.getElementById("Name").value;
var aEmail = document.getElementById("Email").value;
google.script.run.addAName(aName, aEmail);
}
</script>
<script type="text/javascript">
window.mdc.autoInit();
</script>
</body>
Only one parameter can be added to the server function being called. But you can use an array as the one parameter and put multiple values into the array.
var data_Array = [aName, aEmail];
google.script.run
.withSuccessHandler(myClientSideFunction)
.addAName(data_Array);
A value is not automatically returned, you must add a return myValue statement.
function addAName(data) {
var bName, bEmail;
bName = data[0];//Arrays in JavaScript are zero indexed
bEmail = data[1];
//code
return "something";
}
Client Code
<script>
window.sendInputToGS = function() {
var aName = document.getElementById("Name").value;
var aEmail = document.getElementById("Email").value;
var data_Array = [aName, aEmail];
google.script.run
.withSuccessHandler(confirmationBack)
.addAName(data_Array);
}
window.confirmationBack = function(rtrn) {
if (rtrn === 'success') {
}
}
</script>
The success and failure handlers for the async communication between the Apps Script instance and the client-side HTML code are functions in the client-side code, not written in Apps Script (.gs).
When calling your server-side function foo(input), it can be used to call other server-side functions (bar(), baz()) as desired, and use their outputs to form the value that is sent to the client-side success handler.
Example:
.gs
function foo(valFromClient) {
var firstPart = bar(valFromClient);
var secondPart = baz(valFromClient);
return {input: valFromClient, first: firstPart, second: secondPart};
}
function bar(input) {
return "'bar' called, input '" + String(input) + "'.";
}
function baz(val) {
return "'baz' called, input '" + String(val) + "'.";
}
.html
...
<script>
function getServerStuff() {
google.script.run
.withFailureHandler(serverThrewException)
.withSuccessHandler(serverFunctionCalledReturn)
.foo("Hi");
}
function serverThrewException(err) {
console.log(err);
}
function serverFunctionCalledReturn(value) {
console.log(value);
}
</script>
In this example, because our code does not throw any exceptions, the failure handler will never be called, and only the success handler will be called. The browser console would log the object {input: "Hi", first: "'bar' called, input 'Hi'.", second: "'baz' called, input 'Hi'."}.

Alternatives to suggestBox in a Google UiApp

I'm trying to create a relatively simple app (or at least it seemed that way two weeks ago) to catalog periodical intake in a library. I need a form with two boxes: text input for periodical titles and date input for publication date. I then need this form to submit to a Google Spreadsheet. I could just use a generic form, but I need it to autocomplete the periodical title as the information is being entered.
I'm using Google Apps, Spreadsheets, and Sites because they're free and do most of what I want. Here's the sticking point. I can create an HTMLService that autocompletes perfectly from a Google sheet. I basically followed this post exactly.
I can create a script that is a UiApp for submitting to a sheet. I just can't do both with one project. The code follows:
function doGet() {
var doc = SpreadsheetApp.openById(SPREADSHEET_ID);
var app = UiApp.createApplication().setTitle('Periodical Intake');
// Create a grid with 3 text boxes and corresponding labels
var grid = app.createGrid(3, 2);
grid.setWidget(0, 0, app.createLabel('Title:'));
// Text entered in the text box is passed in to pTitle
// The setName method will make those widgets available by
// the given name to the server handlers later
grid.setWidget(0, 1, app.createTextBox().setName('pTitle').setId('pTitle'));
grid.setWidget(1, 0, app.createLabel('Date:'));
grid.setWidget(1, 1, app.createDateBox().setName('date').setId('date'));
// Text entered in the text box is passed in to city.
// Create a vertical panel..
var panel = app.createVerticalPanel();
// ...and add the grid to the panel
panel.add(grid);
// Here's where this script diverges from the previous script.
// We create a horizontal panel called buttonPanel to hold two buttons, one for submitting the contents of the form
// to the Spreadsheet, the other to close the form.
var buttonPanel = app.createHorizontalPanel();
// Two buttons get added to buttonPanel: button (for submits) and closeButton (for closing the form)
// For the submit button we create a server click handler submitHandler and pass submitHandler to the button as a click handler.
// the function submit gets called when the submit button is clicked.
var button = app.createButton('submit');
var submitHandler = app.createServerClickHandler('submit');
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
// For the close button, we create a server click handler closeHandler and pass closeHandler to the close button as a click handler.
// The function close is called when the close button is clicked.
var closeButton = app.createButton('close');
var closeHandler = app.createServerClickHandler('close');
closeButton.addClickHandler(closeHandler);
buttonPanel.add(closeButton);
// Create label called statusLabel and make it invisible; add buttonPanel and statusLabel to the main display panel.
var statusLabel = app.createLabel().setId('status').setVisible(false);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
}
// Close everything return when the close button is clicked
function close() {
var app = UiApp.getActiveApplication();
app.close();
// The following line is REQUIRED for the widget to actually close.
return app;
}
// function called when submit button is clicked
function submit(e) {
// Write the data in the text boxes back to the Spreadsheet
var doc = SpreadsheetApp.openById(SPREADSHEET_ID);
var lastRow = doc.getLastRow();
var cell = doc.getRange('a1').offset(lastRow, 0);
cell.offset(0, 1).setValue(e.parameter.pTitle);
cell.offset(1, 2).setValue(e.parameter.date);
// Clear the values from the text boxes so that new values can be entered
var app = UiApp.getActiveApplication();
app.getElementById('pTitle').setValue('');
app.getElementById('date').setValue('');
// Make the status line visible and tell the user the possible actions
app.getElementById('status').setVisible(true).setText('The periodical ' + e.parameter.pTitle + ' was entered.' +
'To add another, type in the information and click submit. To exit, click close.');
return app;
}​
I could use my getAvailableTags function if it's possible to use jQuery in a UiApp (I don't think it is). The other suggestion is to use suggestBox but it seems that has been deprecated. I'm at my wit's end. It's been two weeks and I feel I haven't gotten anywhere. Can anyone please help a librarian out?
Here is an example of a form built with HTMLService that keeps data in a spreadsheet. I has also a file upload that you don't need but I thought it could interest someone else...
The autocomplete feature should be easy to integrate using you existing code borrowed from Mogsdad.
code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function serverFunc(theForm) {
var fileBlob = theForm.theFile; // This is a Blob.
var name = theForm.name;
var number = theForm.number;
var adoc = DocsList.createFile(fileBlob);
var sh = SpreadsheetApp.openById('1dx0mr4Dy64jqmliTjFyHF7rZW4TZ_PPkWyA_H3WTRcA').getSheetByName('Sheet1');
sh.getRange(sh.getLastRow()+1,1,1,4).setValues([[adoc.getName(),adoc.getUrl(),name,number]]);
return adoc.getUrl();
}
index.html :
<style>
p {
margin:40px;
font-family:arial,sans-serif;
font-size:10pt;
color:#AAA
}
</style>
<p>
Test this file upload form :
<br><br>
<form>
Enter you name <input type="text" name="name" ><br>
Enter your number <input type="text" name="number"><br>
select your file <input type="file" name="theFile"><br>
<input type="button" value="UpLoad" id="button" onclick="google.script.run.withSuccessHandler(cliHandler).serverFunc(this.parentNode)">
</form>
</div><br>
<div id="url" >
</div><br>
<div id="urlText" >
</p>
<script>
function cliHandler(e){
document.getElementById('button').value = "Your file has been uploaded" ;
var divUrl = document.getElementById('url');
divUrl.innerHTML = 'Open the file';
document.getElementById('urlText').innerHTML = "url : "+e;
}
</script>
EDIT : Here is a version based on your code with a working form and autocomplete:
code.gs
function doGet() {
return HtmlService.createTemplateFromFile('Autocomplete').evaluate().setTitle('Periodical Intake');
}
function getAvailableTags() {
var ss = SpreadsheetApp.openById("0Agz7u97dbdECdGh6QVcyb2NVeFByTnlYeU5KcDdSRWc");
var s = ss.getSheetByName("Cataloging Key");
var data = s.getDataRange().getValues();
var headers = 0; // number of header rows to skip at top
var tagColumn = 0; // column # (0-based) containing tag
var availableTags = [];
for (var row=headers; row < data.length; row++) {
availableTags.push(data[row][tagColumn]);
}
return( availableTags );
}
function doPost(e) {
var title = e.title;
var date = e.date;
Logger.log(title+' '+date);
}
Autocomplete.html
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<style>
p {
margin:40px;
font-family:arial,sans-serif;
font-size:10pt;
color:#AAA
}
</style>
<p>
Test this file upload form :
<br><br>
<div>
<form class="ui-widget" >
<input id="title" type=text placeholder="Periodical Title:" name="title" /><br />
<input id="date" type=date placeholder="Publication Date: " name="date" /><br>
<input type="button" value="Submit"
onclick="google.script.run.doPost(this.parentNode)" />
</form>
</div><br>
<div id="url" >
</div><br>
<div id="urlText" >
</p>
<script>
// This code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(buildTagList).getAvailableTags();
});
function buildTagList(availableTags) {
$( "#title" ).autocomplete({
source: availableTags
});
}
</script>