Google sheet web app search data from sheet error - google-apps-script

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)

Related

Google script not retrieving value of HTML textarea prompt

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:

Creating a dialogue box to capture booking details in Google sheets App Script

I am using Google sheets with app script to build a reservations chart for a hotel
Can someone please tell me if there is a way to add a Dialogue box to a google sheet that can ask multiple questions? I have found the Prompt Dialogue box but that seems to allow only one text box for data entry. I have something like this
var result = ui.prompt(
"Let's get to know each other!",
"Please enter your name:",
ui.ButtonSet.OK_CANCEL
);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
ui.alert("Your name is " + text + ".");
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert("I didn't get your name.");
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert("You closed the dialog.");
}
If there isnt something pre-built, can you please recommend how else I can capture data which would then feed a second sheet within the same spreadsheet .
many thanks
You need to use the HTML service
The method you are using is quite limited. To go further than that you would need to create your own HTML file and serve it from Apps Script. The flow of that is:
Create an HTML file in the script editor
Create your HTML form
Write a script on the HTML that calls a function on your gs script.
Sample code
Code.gs
// Creates form on UI
function form() {
var htmlOutput = HtmlService
.createHtmlOutputFromFile('form')
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Add your info');
}
// Uses info passed from rendered HTML to add data to sheet.
function addForm(data){
console.log(data)
SpreadsheetApp.getActiveSpreadsheet().getRange("A1:C1").setValues([data])
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// function to run when server-side script is successful
function onSuccess(){
google.script.host.close()
}
// function to run when form is submitted
function sendForm(){
console.log("RUNNING")
let name = document.getElementById("name").value
let country = document.getElementById("country").value
let DOB = document.getElementById("DOB").value
let data = [name, country, DOB]
// call server side function
google.script.run.withSuccessHandler(onSuccess).addForm(data)
}
</script>
</head>
<body>
<form id="form" onsubmit="sendForm()">
<label for="name">First name:</label><br>
<input type="text" name="name" id="name">
<label for="country">Country:</label><br>
<input type="text" name="country" id="country">
<label for="DOB">DOB:</label><br>
<input type="text" name="DOB" id="DOB">
<input type="submit">
</form>
</body>
</html>
Explanation
When the function form() is run from the script editor, it displays your HTML in the Spreadsheet UI.
This shows a form with three text inputs and a submit button.
The submit button has a onsubmit="sendForm()" which is a function defined within the HTML.
It gets all the info from the form, and then calls google.script.run.withSuccessHandler(onSuccess).addForm(data). This is an asynchronous function that sends a request to the gs file to run the addForm function and then when successful, to run the onSuccess function in the HTML.
The onSuccess simply closes the form.
addForm adds the info to a range in the spreadsheet.
Reference
HTML service
Show Modal Dialog
google.script.run

Triggering mail sending on HTML form submit using Google Apps Script

I created an HTML form which successfully submits data to Google Sheets via Google Apps Script.
Now I would like to trigger a sending of confirmation email to an address entered in the email input field.
I’m really struggling to expand the functionality of my script despite spending many hours on this problem. I would greatly appreciate any help.
The code for the HTML form:
<form action="https://script.google.com/macros/s/AKfycbzz-KveHder1A3CX8GcqZI6GR2MQj66PDRWNKoatIET_LXNqQs/exec" method="post" target="response">
<fieldset>
<legend>Select Foobar</legend>
<label><input type="checkbox" name="Foobar" value="Foo">Foo</label>
<label><input type="checkbox" name="Foobar" value="Bar">Bar</label>
<label><input type="checkbox" name="Foobar" value="Baz">Baz</label>
</fieldset>
<fieldset>
<legend>Choose Xyzzy</legend>
<label><input type="radio" name="Xyzzy" value="Quux">Quux</label>
<label><input type="radio" name="Xyzzy" value="Quuz">Quuz</label>
</fieldset>
<fieldset>
<legend>Enter Personal Details</legend>
<input type="text" placeholder="John Doe" name="Name" required><br>
<input type="email" placeholder="john.doe#example.com" name="Email"><br>
<textarea placeholder="Lorem ipsum dolor sit amet…" name="Description"></textarea>
</fieldset>
<input type="submit" value="Submit">
</form>
<iframe name="response"></iframe>
Which submits to this Google Sheet:
https://docs.google.com/spreadsheets/d/10VHS6bozcdNFYcRskkoONMT8Rt-2CwJ_LJGQWdkTJq4/
The relevant Google Apps Script code:
var sheetName = "Sheet1";
var scriptProperties = PropertiesService.getScriptProperties();
function intialSetup() {
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
scriptProperties.setProperty("key", activeSpreadsheet.getId());
}
function doPost(e) {
var lock = LockService.getScriptLock();
lock.tryLock(3000);
try {
var doc = SpreadsheetApp.openById(scriptProperties.getProperty("key"));
var sheet = doc.getSheetByName(sheetName);
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow() + 1;
var newRow = headers.map(function(header) {
if (typeof e.parameters[header] !== "undefined") {
return header === "Date" ? new Date() : e.parameters[header].join(", ");
} else {
return header === "Date" ? new Date() : e.parameters[header];
}
});
sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]);
return HtmlService.createHtmlOutputFromFile(
"Index"
).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
} catch (e) {
return HtmlService.createHtmlOutputFromFile(
"Error"
).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
} finally {
lock.releaseLock();
}
}
You want to send an email to the inputted email when the submit button is clicked.
If my understanding is correct, how about this answer? In this answer, the email is sent at the Google Apps Script side. Please think of this as just one of several answers.
Modified script:
For example, how about adding the following script after the line of sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]); in your Google Apps Script?
var email = e.parameter.Email;
MailApp.sendEmail({
to: email,
subject: "sample subject",
body: "sample text body",
htmlBody: "sample HTML body"
});
In this script, the inputted email is used as the email.
Note:
From your question, I couldn't find the body of email. If you want to include the inputted values of the form, please tell me.
When you modified the script of Web Apps, please redeploy Web Apps as new version. By this, the script with the latest version is reflected. Please be careful this.
Reference:
Class MailApp
If I misunderstood your question and this was not the direction you want, I apologize.
Added:
When you want to send the HTML body of email with a HTML file which is separated from Google Apps Script, you can use the following script.
Sample script:
MailApp.sendEmail({
to: email,
subject: "sample subject",
body: "sample text body",
htmlBody: HtmlService.createHtmlOutputFromFile("htmlBody").getContent()
});
In this case, when a HTML file with the filename of htmlBody is added to the script editor including the Google Apps Script, HtmlService.createHtmlOutputFromFile("htmlBody").getContent() returns the raw HTML as the string including the tags.
Reference:
Class HtmlService

How do I pass html data form a Google sidebar a variable in gs code

I have a sheet which tracks pupil progress against a set of objectives - pupil name across the top, objectives listed down the left hand side. Each pupil is in a group - in the example below the groups are indicated by SK, IO and NU.
I have created a sidebar with various filters.
The issue I am having is with the filter where the user will enter a group name, when the filter button is clicked all of the columns will hide except for the columns which contain the entered group name. I have the following code:
from the .gs sheet:
function showGroup(group) {
for(var i=2; i<lastCol-36; i++) {
if(data.getCell(8, i).getValue() != group) {
sheet.hideColumns(i);
}
}
}
from the html sheet:
<form id="filterGroups" >
<input type="text" value="" id="groupName">
<input type="button" value="Filter"
onclick="google.script.run.showGroup(filterGroups)" />
The closest I have got to success is to hide all columns providing the form id matches the parameter passed to google.script.run.
You want to show only the columns with the values that user inputted. And you want to hide other columns except for them.
The values that user inputted are at row 8 of the sheet 'Science Year Group'.
If my understand of your question is correct, how about this modification?
Modification points:
If several strings (SK, NU) are put in the text box, if(data.getCell(8, i).getValue() != group){} is always false.
Give a name of name="groupName" to the text box. Using this, it retrieves the value using group.groupName at GAS side.
If the name is not given, you can retrieve the value using group[""].
I felt that when sheet.hideColumns(i) is used in the for loop, the process cost is high. So I used Sheets API for your situation.
By this, the hide and show of each column can be controlled by one API call.
At first, in order to use Sheets API, please enable Sheets API at Advanced Google Services and API console. You can see about how to enable Sheets API at here.
Modified scripts:
GAS
function showGroup(group) {
var unhide = group.groupName.split(",").map(function(e){return e.trim().toUpperCase()});
var values = sheet.getRange(8, 2, 1, (lastCol - 36) - 2).getValues()[0];
var template = {updateDimensionProperties:{properties:{},range:{sheetId:sheet.getSheetId(),dimension:"COLUMNS"},fields:"hiddenByUser"}};
var r = values.map(function(e, i) {
var t = JSON.parse(JSON.stringify(template));
if (~unhide.indexOf(e)) {
t.updateDimensionProperties.properties.hiddenByUser = false;
} else {
t.updateDimensionProperties.properties.hiddenByUser = true;
}
t.updateDimensionProperties.range.startIndex = i + 1;
t.updateDimensionProperties.range.endIndex = i + 2;
return t;
});
Sheets.Spreadsheets.batchUpdate({"requests": r}, ss.getId());
}
HTML
<form id="filterGroups" >
<input type="text" value="" id="groupName" name="groupName">
<input type="button" value="Filter" onclick="google.script.run.showGroup(filterGroups)">
</form>
Note:
In this modified script, when SK, NU is put in the text box, only columns with SK, NU are shown. Other columns are hidden.
Reference:
UpdateDimensionPropertiesRequest
If I misunderstand your question, please tell me. I would like to modify it.
Edit :
About Can you show me how to pass html form data to GAS functions? of your comment, I show you a sample script using your HTML form. The HTML form is as follows.
HTML
In this sample, the value is sent to showGroup(filterGroups) using google.script.run().
<form id="filterGroups" >
<input type="text" value="" id="groupName" name="groupName">
<input type="button" value="Filter" onclick="google.script.run.showGroup(filterGroups)">
</form>
GAS
In this sample, the value from HTML form is retrieved by group.groupName.
function showGroup(group) {
Logger.log(group.groupName)
}

HtmlService form submit opens new tab with foo bar URL

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