I am creating a form in which I have added few items of type SCALE and I want the user to select from a scale of 1 to 3.
Now I want to dynamically add all these selected values such as the sum = selected value of scaleA + ..scaleB+ ..ScaleN.
So far I have managed to get all the SCALE items, but I am unable to get the value that use has currently selected.
The API gives only following methods getUpperBound() and getLowerBound() where as I want to get the value the user has currently selected.
Is there a way I can achieve this?
Note: I want to display the user the sum of selected value right away as he is filling in the form.
The piece of code that I have written so far
function myFunction() {
var form = FormApp.getActiveForm();
var items = form.getItems(FormApp.ItemType.SCALE);
for (var i = 0; i < items.length; i++)
Logger.log(items[i].getId() + ':Title ' + items[i].getTitle()+ ':ScaleItem '+items[i].asScaleItem());
}
To make a dynamic form you will have to use google apps scripts to create your own from using HTML service. Like So: https://script.google.com/macros/s/AKfycby5b0Q2cuDSTl8VDIG60-9lnklAgeaZlXwmZq2slRG4h-fx6og/exec
Native form application from google cannot be used for making a dynamic form that updates while the form is live.
Html File: "ScaleForm", code source: http://www.w3schools.com/tags/tag_output.asp
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div id = "formDiv">
<form id = "scaleForm" oninput="x.value=parseInt(a.value)+parseInt(b.value)">
0
<input type="range" id="a" name="a" value="0" min ="0" max ="3">
3 <br>
+ <br> 0
<input type="range" id="b" name="b" value="0" min ="0" max ="3">
3 <br>
=
<output id = "c" name="x" for="a b"></output> <br>
<input type ="button" value ="Submit" onclick ="formSubmit()">
</form>
</div>
<br>
Values Submitted shown Below:
<div id="submittedValue">
</div>
<script>
function formSubmit(){
var formvalues = []
var d = new Date();
formvalues[0] = d.toString();
formvalues[1] = document.getElementById("a").value
formvalues[2] = document.getElementById("b").value
formvalues[3] = document.getElementById("c").value
var sub = document.getElementById("submittedValue")
sub.innerHTML = "Value 1: " +formvalues[1] +"<br>Value 2: "+formvalues[2] +"<br>Total: "+formvalues[3]
google.script.run.recordValues(formvalues)
}
</script>
</body>
</html>
Google Script code:
function doGet() {
return HtmlService.createTemplateFromFile('ScaleForm')
.evaluate()
.setTitle('Scale Form for stack overflow');
}
function recordValues(formvalues){
var scale1 =formvalues[0]
var scale2 = formvalues[1]
var sum = formvalues[2]
// The above assignments are for reference sake only they are not used
var Ss = SpreadsheetApp.openById("Paste your Spreadsheet ID here to record the values")
var Sheet = Ss.getSheetByName("Responses")
Sheet.appendRow(formvalues)
}
How to run this:
In scripts.google.com create a script file and an HTML file named "ScaleForm".
Copy the HTML code the HTML file and script to the script file.
Use publish menu to deploy this as a web app and you should be good to go.
More details on web App can be found here: https://developers.google.com/apps-script/guides/web
Related
I want to search data from google sheet and show it in form by web app.
PAN is unique and 5 digit number. When we enter PAN ,5 digit number to( PAN) input form and click update button then it should search data for PAN in sheet and if match then bring entire row to the web form, otherwise it show unavailable.
When we enter PAN number and click update button , it show wrong data in form.
But when we check it by Logger.log() , it show right data .
I don't know and figure out why it show wrong data in web form when we click update button, Please help me and let me know what is the cause for this issue
function doGet(e)
{
return HtmlService.createHtmlOutputFromFile("page");
}
function searchData(pan)
{
var ss=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
//var nameList=ss.getRange("A1:A").getValues().flat();
//var panList=ss.getRange("B1:B").getValues().flat();
//var aadharList=ss.getRange("c1:c").getValues().flat();
//var emailList=ss.getRange("d1:d").getValues().flat();
//var phnList=ss.getRange("e1:e").getValues().flat();
var data=ss.getRange(1,1,ss.getLastRow(),5).getValues();
var panList=data.map(function(r){return r[1];});
var nameList=data.map(function(r){return r[0];});
var aadharList=data.map(function(r){return r[2];});`enter code here`
var emailList=data.map(function(r){return r[3];});
var phnList=data.map(function(r){return r[4];});
var index=panList.indexOf((pan));
if(index>-1)
{
var name=nameList[index];
var aadhar=aadharList[index];
var email=emailList[index];
var phone=phnList[index];
return [name,pan,aadhar,email,phone]
}
else
{ return "unavailable"}
}
Logger.log(searchData(66666))
//html file..(page.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1> Web App </h1>
<label> Name </label>
<input type="text" id="username">
<label> PAN</label>
<input type="number" id="userpan">
<label> Aadhar </label>
<input type="number" id="useraadhar">
<label> Email </label>
<input type="text" id="useremail">
<label> Telepnoe </label>
<input type="text" id="userphone">
<button id="btn"> Update </button>
<script>
//document.getElementById("userpan").addEventListener("input",search);
document.getElementById("btn").addEventListener("click",search);
function search()
{
var pan=document.getElementById("userpan").value;
if(pan.length==5)
{
google.script.run.withSuccessHandler(test).searchData(pan);
function test(s)
{
document.getElementById("username").value=s[0];
document.getElementById("userpan").value=pan;
document.getElementById("useraadhar").value=s[2];
document.getElementById("useremail").value=s[3];
document.getElementById("userphone").value=s[4];
}
}
}
</script>
</body>
</html>
From But when we check it by Logger.log() , it show right data . and your showing script, I thought that the reason of your issue might be due to that the values of panList are the number while var pan=document.getElementById("userpan").value is the string. In this case, even when the inputted value to the input tag is the number 66666, the value of var pan=document.getElementById("userpan").value is the string. By this, var index=panList.indexOf((pan)); is always -1.
If your script is simply modified, please modify it as follows.
From:
var data=ss.getRange(1,1,ss.getLastRow(),5).getValues();
To:
var data = ss.getRange(1, 1, ss.getLastRow(), 5).getDisplayValues();
By this, when pan of 66666, which is the string, is sent from Javascript to Google Apps Script, data retrieved by getDisplayValues() is the string. By this, var index=panList.indexOf((pan)); can be worked.
Note:
I thought that your Google Apps Script might be able to reduce the process cost as follows.
function searchData(pan) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range = sheet.getRange("B1:B" + sheet.getLastRow()).createTextFinder(pan).matchEntireCell(true).findNext();
if (range) {
return sheet.getRange(range.getRow(), 1, 1, 5).getValues()[0];
}
return "unavailable";
}
Note:
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
getDisplayValues()
createTextFinder(findText)
I have a HTML prompt for a spreadsheet with 2 input spaces, one for "usuario" which it a text input and the other one for "mensaje" which is textarea.
My script needs to retrieve both values, intert "mensaje" in a specific cell, and download a PDF with "usuario" in the name.
Everything works perfect when it has 2 input type="text", but i need the second one to allow multiple rows so I had to change it.
Now it seems like the textarea "mensaje" information is not transmiting correctly to the script, it isn't inserted into the cell. Everything else works normally.
It doesn't show any error, it just doesn't retrieve the values, so it doesn't insert it, so the downloaded PDF is blank.
I'm not sure what I would need to change to make textarea work correctly, I don't have a lot of experience programing, mostly mashing together parts I found online to make it do what I want.
IndexTexto.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<form id="textform" style="font-size:16px">
Usuario:<br>
<input type="text" name="usuario" style="width: 300px;">
<br>
<br>
Mensaje:<br>
<textarea id="mensaje" rows="14" cols="95"></textarea>
<br><br><br>
<input type="button" value="Descargar" class="action " style="font-size:16px" style="height: 150px;" style="text-align:center;"
onclick="google.script.run
.withSuccessHandler(google.script.host.close)
.descargarTexto(this.parentNode)" />
</form>
</html>
Relevant parts of DescargarTexto.gs
function promptTexto() {
var html = HtmlService.createHtmlOutputFromFile('IndexTexto').setSandboxMode(HtmlService.SandboxMode.IFRAME).setHeight(400).setWidth(700);
SpreadsheetApp.getUi().showModalDialog(html, 'Ingresar texto');
}
function descargarTexto(form) {
SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutput('5').setHeight(10).setWidth(100), "Creando");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Link de pago');
var sheetId = sheet.getSheetId();
var usuario = form.usuario
var mensaje = form.mensaje
sheet.getRange(15,3).setValue(mensaje)
SpreadsheetApp.flush();
var range = sheet.getRange(15,3)
var values = range.getValues()
Logger.log(mensaje)
Logger.log(values)
var date = Utilities.formatDate(new Date(), "GMT+3", "dd-MM-yy")
var filename = usuario + "_" + date + ".pdf"; // Please set the filename here.
You are trying to access undefined object in form.mensaje. If you try to print the form in your descargarTexto(form) function. It will print something like this: {=DEF, usuario=ABC}. The key name for mensaje is not defined. This can be fixed by adding name="mensaje" attribute to mensaje text area.
Note: You can view logs at Executions tab of your App Script project
Your code should look like this:
<textarea id="mensaje" name="mensaje" rows="14" cols="95"></textarea>
Example:
Output:
I am working on a google add-on which uses an HTML sidebar. The sidebar has an HTML form with checkboxes. I want some of the checkboxes to be checked when the user opens the sidebar, based on some User Properties that will already have been initialized. (When the form submits, the Properties are updated. They all start as on). Here is the code for the sidebar:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Settings</title>
<script>
function onSettingsOpen()
{
Logger.log("In the script");
console.log("In the script");
document.getElementById(propsList[0]).checked = (allPreferences.getProperty(propsList[0]) === "true");
document.getElementById(propsList[1]).checked = (allPreferences.getProperty(propsList[1]) === "true");
document.getElementById(propsList[2]).checked = (allPreferences.getProperty(propsList[2]) === "true");
document.getElementById(propsList[3]).checked = (allPreferences.getProperty(propsList[3]) === "true");
document.getElementById(propsList[4]).checked = (allPreferences.getProperty(propsList[4]) === "true");
document.getElementById(propsList[5]).checked = (allPreferences.getProperty(propsList[5]) === "true");
}
</script>
</head>
<body onload="onSettingsOpen()">
<form id="baseSettings" onsubmit="event.preventDefault(); google.script.run.processForm(this)">
<h2>What settings would you like to be on? Please select all that apply.</h2>
<br>
<input type="checkbox" name="checks" value="spaces" id="spaces">Double spaces
<br>
<input type="checkbox" name="checks" value="punctuation" id="punctuation">Punctuation outside of quotes
<br>
<input type="checkbox" name="checks" value="caps" id="caps">Capitilazation at beginning of sentences
<br>
<input type="checkbox" name="checks" value="contractions" id="contractions">Contractions
<br>
<input type="checkbox" name="checks" value="numbers" id="numbers">Small numbers
<br>
<input type="checkbox" name="checks" value="repWords" id="repWords">Repeated words
<br>
<br>
<input type="submit" value="Submit">
</form>
</body>
So as far as I can tell, the Logger.logs and Console.logs aren't running, which implies that the function just isn't running. However, I could not find documentation on running Console/Logger Log functions in an HTML script file; I'm not sure if that is actually the telling factor. What I can't figure out is where to run the function so that it can actually effect the checkboxes. I fear that running it onload of the body won't actually do anything to the checkboxes- it would have to run within the form itself. Where should I call the function?
Here is my create settings pane function:
function openSettings ()
{
populateData ();
initializePreferences();
Logger.log("Data is initialized; pref 1 = " +
allPreferences.getProperty(propsList[0]));
var htmlOutput = HtmlService
.createHtmlOutputFromFile('Settings.html')
.setWidth(300)
.setTitle("Settings");
DocumentApp.getUi().showSidebar(htmlOutput);
}
Any help appreciated!
You could use a function like this when you load the sidebar
<script>
window.onload=function(){
google.script.run
.withSuccessHandler(function(data){
//initialize your checkboxes here
})
.getPropertData();//go to server side to get access to PropertiesService data
};
Client to Server Communication
Your onSettingsOpen references propsList, but this is undefined. You should pass the data in the function by giving the function an argument, e.g. onSettingsOpen(preferences).
Assuming you are storing these preferences in some PropertiesService, when you call Properties.getProperties() you get back an object with key, value pairs. If you make these match your HTML input "id" attributes, you can just lookup the values in the object by passing the id as a key.
Inside the sidebar:
<script>
google.script.run.withSuccessHandler(onSettingsOpen).getAllPreferences();
// #param {Object} preferences - key, value pairs from Properties.getProperties()
function onSettingsOpen(preferences)
{
console.log("In the script");
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (let i = 0; i < checkboxes.length; ++i) {
checkboxes[i].checked = preferences[checkboxes[i].id];
}
}
</script>
Server-side code would need the appropriate getAllPreferences function:
function getAllPreferences() {
return PropertiesService.getUserProperties().getProperties();
}
I am attempting to build a UI for a spreadsheet using GAS HtmlService. The HTML below is a very simple form with a single text box that pulls a value ("Kristina") from the sheet, successfully. However, when I try to submit the form a new tab is opened in Chrome that attempts to open the URL "bffc95ee-ff64-4d2c-xxxx-19d9824eb4b4.foo.bar/?fname=Kristina" with "xxxx" replacing more random letters and numbers (just in case). At no point do I use the words "foo.bar" in my code, so I'm pretty sure that that part isn't coming from me. It does not change each time or after logging out and back in. I'm getting the same result on two different computers.
<html>
<body>
<div>
<form id="formtest1">
<label>First Name</label>
<input name="fname" type="text" maxlength="255" value="<?= fname ?>"/>
<input type="submit" value="Submit"
onclick="google.script.run.processForm(document.getElementById('formtest1'));
google.script.host.close()"/>
</form>
</div>
</body>
</html>
The above is being displayed using the following function:
function htmltest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var html = HtmlService.createTemplateFromFile("HTML");
html.fname = sht.getRange(2, 3).getValue();
ss.show(html.evaluate());
};
If I understand correctly, the "google.script.run.processForm(...)" script in the HTML should trigger the following function, as set up in the projects triggers:
function onFormSubmit(){
Browser.msgBox("Test");
};
But it doesn't appear to do so as the form doesn't close and the msgBox doesn't appear. Only the foo bar URL in a new tab.
Hopefully I've explained the issue clearly and am not making an embarrassing mistake.
You cannot use a real "submit" button with google.script.run (this is a documented restriction in the user guide). Change it to "button" and it should work fine.
The project trigger onFormSubmit() will be triggered by a submission via the Forms Service. There is no relationship between this trigger and your HTML code; they are two different ways to interact with users.
An html forms pattern is shown in the HTML Service documentation here, and the script below is an adaptation of it.
Code.gs
The only real change from your original is that onFormSubmit() has been replaced with processForm(form), which includes a parameter, for the object that will be passed from the html code.
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "htmltest",
functionName : "htmltest"
}];
sheet.addMenu("Custom Menu", entries);
};
function htmltest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var html = HtmlService.createTemplateFromFile("HTML");
html.fname = sht.getRange(2, 3).getValue();
//Logger.log( html.getCodeWithComments() );
ss.show(html.evaluate());
};
function processForm(form){
var fname = form.fname;
Browser.msgBox("Test - " + fname);
};
HTML.html
This is a modification of your original, echoing the pattern from the documentation. The form submission SuccessHandler is a one-liner, which closes the dialog. Once it completes, the server-side function is invoked with the form content, retrieved using this.parentNode (to refer to the form).
There are other ways - see Get value of html text box in Apps Script function for a different approach.
<html>
<script type="text/javascript">
// SuccessHandler to close form
function close() {google.script.host.close();}
</script>
<body>
<div>
<form>
<label>First Name</label>
<input name="fname" type="text" maxlength="255" value="<?= fname ?>"/>
<input type="button" value="Submit" onclick="google.script.run
.withSuccessHandler(close)
.processForm(this.parentNode)"/>
</form>
</div>
</body>
</html>
Just add this to your script tag on your html file.
// 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);
Source: HTML Service: Communicate with Server Functions
I have a page which assign some values to arrays when a function named 'hndlr' is called.code of the file is given bellow
<html>
<head>
<title>Search Example</title>
</head>
<body>
<script>
var pageName = new Array();
var pageLink = new Array();
var pageDetails = new Array();
function hndlr(response) {
// here I assign values to arrays pageName,pageLink,pageDetails using a for loop
}
// Some codes (I cant change anything in here)
// call the function hndlr here (I cant change anything in here)
</script>
</body>
</html>
I want to take pageName array into a checkbox list and pass the pageLink of selected checkboxes to another file.
I tried using bellow code just before the end of the body tag. but it isn't passing any data to next page(b.php)
<form action="b.php" method="post">
<script>
for (var j = 0; j < 5; j++) {
document.write("<input type='checkbox' name='formDoor[]' id='"+j+"' value= '' />"+pageName[j]+"<br />");
document.getElementById(j).value = pageLink[j];
}
</script>
<input type="submit" name="formSubmit" value="Submit" />
</form>
When I print the output, It displays 'undefined' strings just before the check boxes.
That means pageName[j] doesn't return any value.
problem is, these arrays are not visible to second part(part I tried with check boxes)
Please show me the way to do this..
Weird, your code is working for me (click the code box to show it): http://codepad.viper-7.com/4IVobE
You can't submit the form on this site but you can see that the arrays are accessible within the second script tag. I also tried it on my local server and after submitting the form I was able to access the values in b.php just fine.