Email attachments by FileID - google-apps-script

I have a script that creates a document from a template and updates the sheet with the FileID of the doc that was just create, this is working fine. What I am having trouble with is getting email to attach the file from the fileID column in my sheet.
Screen snip of Sheet
Here is the code of the email script without any scripting for adding the attachment. I have tried many things and just can't get the attachment piece to work. I also want to mention that this script is to be called from menu item and process all lines in the sheet with email addresses.
/**
function getData(sheetName) {
var data = SpreadsheetApp.getActive().getSheetByName(sheetName).getDataRange().getValues();
return data;
}
function renderTemplate(template, data) {
var output = template;
var params = template.match(/\{\{(.*?)\}\}/g);
params.forEach(function (param) {
var propertyName = param.slice(2,-2); //Remove the {{ and the }}
output = output.replace(param, data[propertyName] || "");
});
return output;
}
function rowsToObjects(rows) {
var headers = rows.shift();
var data = [];
rows.forEach(function (row) {
var object = {};
row.forEach(function (value, index) {
object[headers[index]] = value;
});
data.push(object);
});
return data;
}
/**
* Sends an email for each row.
*/
function sendEmails() {
var templateData = getData("Templates");
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var emailSubjectTemplate = templateData[1][0]; //Cell A2
var emailBodyTemplate = templateData[4][0]; //Cell A5
var emailData = getData("Data");
emailData = rowsToObjects(emailData);
emailData.forEach(function (rowObject) {
var subject = renderTemplate(emailSubjectTemplate, rowObject);
var body = renderTemplate(emailBodyTemplate, rowObject);
MailApp.sendEmail(rowObject["Email"], subject, body)
});
}

Related

when i run my script to fetch data from other 2 sheets it is arranged the shown in picture of master sheet

master sheet
this is my code
the names are displayed under names numbers to be displayed under numbers but it is displayed under names ..I have 2 sheets named as{name,number} and a master sheet contains id,name number.
when i run the script it ftches data but not accordingly
function addMenu()
{
var menu = SpreadsheetApp.getUi().createMenu('Merge');
menu.addItem('Run Script', 'MergeSheets');
menu.addToUi();
}
function onOpen()
{
addMenu();
}
//combine data from multiple sheets
function MergeSheets() {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var data = null;
var RetrieveSheet = null;
var PasteSheet = ss.getSheetByName("Master");
var sheets = ['Name','Number'];
PasteSheet.getRange(2,1,PasteSheet.getLastRow(),PasteSheet.getLastColumn()).clear();
for (var i =0; i<sheets.length; i++){
RetrieveSheet = ss.getSheetByName(sheets[i]);
if (RetrieveSheet.getName() != 'Master'){
data = RetrieveSheet.getRange(2,1,RetrieveSheet.getLastRow(),RetrieveSheet.getLastColumn());
data.copyTo(PasteSheet.getRange(parseInt(PasteSheet.getLastRow())+1,1));
}
}
}
//update data changes to each sheets
function updateBasedSheet()
{
var master = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master');
var valueMaster = master.getRange(2, 1, master.getLastRow(), master.getLastColumn()).getValues();
var Name = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Name');
var Number = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Number');
var dataName = valueMaster.filter( function(item){
return item[2] === 'Name';
}
);
var Number = valueMaster.filter( function(item){
return item[2] === 'Number';
});
Name.getRange(1, 3, dataName.length, dataName[0].length).setValues(dataName);
Number.getRange(1, 3, dataNumber.length, dataNumber[0].length).setValues(dataNumber);
}
If you simply want to join 2 sheets, and they have same length and id correspondesce, you can use
var data1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Name').slice(1);
var data2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Number').slice(1);
var mergedData = data1.map( (index, row) => row.concat(data2[index]) );
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master')
.getRange(2, 1, mergedData.length, mergedData[0].length)
.setValues(mergedData);

How to display info from other sheets, specific to text in cells

Our company works at different properties repairing appliances, I would like to build a database to search up the information on each appliance at specific properties and in their specific apt/units, I created a form to start this process, but I need help with some complex coding.
I first created a box for the property, then I created an "Apt/Unit" box. The idea is when I select a property, the units tied to that property are shown in dropdown/type searchable list in the Apt/Unit box.
I then created an "Appliance type" box. The idea is when the "Apt/Unit" is selected, it will display the dropdown/type searchable list of the appliances tied to that specific "Apt/Unit".
Then I created boxes for the info for the appliance (Brand, Model #, Serial #, & Color), this is a bit more self-explanatory - once the appliance type is selected, it will display the respective information for each box for that appliance.
Here's the link to the Google sheet: https://docs.google.com/spreadsheets/d/1JZhEYjk5xVN3uOc_Ucb8HFr6d96XQ2Q_ehAd-d_o0ME/edit?usp=sharing
Any help is appreciated!
non-scripted solution:
=IFERROR({INDEX(IFERROR(Data!A1:G1/0)); Data!A1:G1; QUERY({Data!A2:G}, "where 1=1 "&
IF(C10="",,"and lower(Col1) contains '"&LOWER(C10)&"'")&
IF(C12="",,"and Col2 = "&C12)&
IF(C14="",,"and lower(Col3) contains '"&LOWER(C14)&"'")&
IF(C16="",,"and lower(Col4) contains '"&LOWER(C16)&"'")&
IF(C18="",,"and lower(Col5) contains '"&LOWER(C18)&"'")&
IF(C20="",,"and lower(Col6) contains '"&LOWER(C20)&"'")&
IF(C22="",,"and lower(Col7) contains '"&LOWER(C22)&"'"), 0)}, {"";"no data"})
demo sheet
Here is third variant of the script:
// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');
function onLoad() { reset() }
function reset() {
SS.toast('Please wait...');
SHEET_USERFACE.getRange('c9:c21').clearContent();
SHEET_USERFACE.getRange('c9:c13').clearDataValidations();
var obj = make_obj_from_data();
update_menu_prop(obj);
update_menu_unit(obj);
update_menu_type(obj);
SS.toast('The sheet has been reset');
}
function onEdit(e) {
if (e.range.getSheet().getName() != 'Userface') return;
if (e.range.columnStart != 3) return;
// Property menu
if (e.range.rowStart == 9) {
e.source.toast('Please, wait...');
SHEET_USERFACE.getRange('c11:c21').clearContent();
SHEET_USERFACE.getRange('c11:c13').clearDataValidations();
var obj = make_obj_from_data();
update_menu_unit(obj);
update_menu_type(obj);
e.source.toast('The sheet has been updated');
}
// Apt/Unit menu
if (e.range.rowStart == 11) {
e.source.toast('Please, wait...');
SHEET_USERFACE.getRange('c13:c21').clearContent();
SHEET_USERFACE.getRange('c13').clearDataValidations();
var obj = make_obj_from_data();
update_menu_type(obj);
e.source.toast('The sheet has been updated');
}
// Applicance type menu
if (e.range.rowStart == 13) {
e.source.toast('Please, wait...');
SHEET_USERFACE.getRange('c15:c21').clearContent();
var obj = make_obj_from_data();
update_brand_model_serial_color(obj);
e.source.toast('The sheet has been updated');
}
}
function make_obj_from_data() {
var data = SHEET_DATA.getDataRange().getValues().slice(1);
var obj = {};
for (let row of data) {
var [prop, unit, type, ...etc] = row;
try {
obj[prop][unit][type] = etc;
}
catch(e) {
try {
obj[prop][unit] = {}; obj[prop][unit][type] = etc;
}
catch(e) {
obj[prop] = {}; obj[prop][unit] = {}; obj[prop][unit][type] = etc;
}
}
}
return obj;
}
function update_menu_prop(obj) {
var cell = SHEET_USERFACE.getRange('c9');
try {
var list = Object.keys(obj);
set_data_validation(cell, list);
} catch(e) {
console.log('update_menu_prop(obj)');
console.log(e);
}
}
function update_menu_unit(obj) {
var prop = SHEET_USERFACE.getRange('c9').getValue();
var cell = SHEET_USERFACE.getRange('c11');
try {
var list = Object.keys(obj[prop]);
set_data_validation(cell, list);
} catch(e) {
console.log('update_menu_unit(obj)');
console.log(e);
}
}
function update_menu_type(obj) {
var prop = SHEET_USERFACE.getRange('c9').getValue();
var unit = SHEET_USERFACE.getRange('c11').getValue();
var cell = SHEET_USERFACE.getRange('c13');
try {
var list = Object.keys(obj[prop][unit]);
set_data_validation(cell, list);
if (list.length == 1) update_brand_model_serial_color(obj)
} catch(e) {
console.log('update_menu_type(obj)');
console.log(e);
}
}
function update_brand_model_serial_color(obj) {
var [prop,,unit,,type] = SHEET_USERFACE.getRange('c9:c13').getValues();
try {
var [brand, model, serial, color] = obj[prop][unit][type];
var arr = [[brand],[''],[model],[''],[serial],[''],[color]];
SHEET_USERFACE.getRange('c15:c21').setValues(arr);
} catch(e) {
console.log('update_brand_model_serial_color(obj)');
console.log(e);
}
}
function set_data_validation(cell, list) {
var rule = SpreadsheetApp.newDataValidation().requireValueInList(list).build();
cell.setDataValidation(rule);
// put the value in the cell if there is just one element in the list
if (list.length == 1) cell.setValue(list[0]);
}
Here is my sheet.
It works about that way as it does any similar interface. You select the first menu and it changes data validation for the second menu and cleans the third menu. Then you select the second menu and it changes the third one. As soon as you change the third menu it fills the rest fields.
Since you're using just the three menus and they supposed to be changed step by step I decided to 'hardcode' them. It's not the best practice and there can be problems if/when you decide to change the functionality. But for this particular case I think the 'hardcoding' is forgivable. It works relatively fast and the code is relatively readable.
Just for fun I've made it. But this is overkill:
// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');
function onLoad() { reset() }
function onEdit(e) {
if (e.range.getSheet().getName() != 'Userface') return;
if (e.range.columnStart != 3) return;
if (![9,11,13,15,17,19,21].includes(e.range.rowStart)) return;
e.source.toast('Please, wait...');
set_filter(e.range.offset(0,-1).getValue(), e.value);
set_all_menus();
e.source.toast('The sheet has been updated');
}
function reset() {
SS.toast('Please wait...');
try { SHEET_DATA.getFilter().remove() } catch(e) {}
SHEET_USERFACE.getRange('c9:c21').clearContent().clearDataValidations();
set_all_menus();
SS.toast('The sheet has been updated');
}
function set_all_menus() {
var data = SHEET_DATA.getDataRange().getDisplayValues().filter((_,i) => !SHEET_DATA.isRowHiddenByFilter(i+1));
set_menu(data, 'b9', 'c9');
set_menu(data, 'b11', 'c11');
set_menu(data, 'b13', 'c13');
set_menu(data, 'b15', 'c15');
set_menu(data, 'b17', 'c17');
set_menu(data, 'b19', 'c19');
set_menu(data, 'b21', 'c21');
}
function set_menu(data, title, cell) {
var menu_title = SHEET_USERFACE.getRange(title).getValue();
var menu_cell = SHEET_USERFACE.getRange(cell);
var col_index = data[0].indexOf(menu_title);
var menu_list = [...new Set([...data.map(e => e[col_index])])].slice(1);
var menu_rule = SpreadsheetApp.newDataValidation().requireValueInList(menu_list).build();
menu_cell.setDataValidation(menu_rule);
}
function set_filter(column_title, value) {
// get all the data and col index
var [header, ...data] = SHEET_DATA.getDataRange().getValues();
var col_index = header.indexOf(column_title);
// unhide all values of the given column
var clear = SpreadsheetApp.newFilterCriteria().setHiddenValues([]).build();
var range = SHEET_DATA.getDataRange();
var filter = range.getFilter() || range.createFilter()
filter.setColumnFilterCriteria(col_index+1, clear);
// get the values to hide
var col_data = data.map(e => e[col_index]);
var filtered = col_data.filter( (e, i) => e != value && SHEET_DATA.isRowHiddenByFilter(i+1) );
var to_hide = col_data.filter( e => e != value );
var hidden = [...new Set([...filtered, ...to_hide])];
// hide the values with the filter
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hidden).build();
var range = SHEET_DATA.getDataRange();
var filter = range.getFilter() || range.createFilter()
filter.setColumnFilterCriteria(col_index+1, criteria);
}
Here is the sheet.
It works quite slow. I'd propose to use the native filters instead. Basically the script turns on and off the filters an changes data validation for the dropdown menus respectively.
Update
Here another version of the script. It works much faster but it uses the 'helper sheet' to store temporary data (the filtered table). You can hide the 'helper sheet' if you want.
// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');
var SHEET_HELPER = SS.getSheetByName('Helper'); // the hidden sheet with temp data
var PROPERTY_LIST = [...new Set(SHEET_DATA.getRange('a2:a').getValues().flat())]; // 'Property' list
var DATA_OBJ = {};
function onLoad() { reset() }
function onEdit(e) {
var {range, source, value} = e;
if (range.getSheet().getName() != 'Userface') return;
if (range.columnStart != 3) return;
if (![9,11,13,15,17,19,21].includes(range.rowStart)) return;
source.toast('Please, wait...');
// reset whenever the first menu is changing
if (range.rowStart == 9) {
reset();
source.getRange('c9').setValue(value);
}
var col_header = range.offset(0,-1).getValue();
update_sheet_helper(col_header, value);
update_all_dropdown_menus();
source.toast('The sheet has been updated');
}
function reset() {
SS.toast('Please wait...');
// copy data from SHEET_DATA to SHEET_HELPER
SHEET_USERFACE.getRange('c9:c21').clearContent().clearDataValidations();
SHEET_DATA.getDataRange().copyTo(SHEET_HELPER.clearContents().getRange(1,1));
update_data_obj();
update_all_dropdown_menus();
SS.toast('The sheet has been updated');
}
// make DATA_OBJECT from SHEET_HELPER
function update_data_obj() {
DATA_OBJ = {};
var [header, ...data] = SHEET_HELPER.getDataRange().getValues();
for (let i in header) DATA_OBJ[header[i]] = data.map(e => e[i]);
DATA_OBJ['Property'] = PROPERTY_LIST; // let 'Property' list will be full always
}
// remove from SHEET_DATA_HELPER all the rows
// that have no given value in column with given title
function update_sheet_helper(col_title, value) {
var [header, ...data] = SHEET_HELPER.getDataRange().getValues();
var col_index = header.indexOf(col_title);
data = data.filter(k => k[col_index] == value);
var table = [header, ...data];
SHEET_HELPER.clearContents().getRange(1,1,table.length, table[0].length).setValues(table);
update_data_obj();
}
function update_all_dropdown_menus() {
SHEET_USERFACE.getRange('b9:c21').getValues().forEach((row,i) => {
if (row[0] != '') set_data_validation(DATA_OBJ[row[0]], 'c' + (i+9));
});
function set_data_validation(data, cell_address) {
var menu_list = [...new Set([...data])]; // remove duplicates from the array
var menu_rule = SpreadsheetApp.newDataValidation().requireValueInList(menu_list).build();
var cell_range = SHEET_USERFACE.getRange(cell_address)
cell_range.setDataValidation(menu_rule);
if (menu_list.length == 1) cell_range.setValue(menu_list[0]);
}
}
The sheet is here.

Execute app script with 2 tags which will determine filter to apply and spreadsheet sheet

I'm on a project in which I get stuck just on the final step.
let me explain:
my project to filter data and move the filtered data to another spreadsheet. All work properly without issues but something happened and the issue is that I need to input dynamic data as filter and sheet name. I created 2 variables location which will determine the filter and sectionSelect which will determine the sheet name.
my goal is to send the data through the web with its tag to be filtered in the desired sheet.
FYI: the app script is bound to a gsheet.
Here is the code:
function doGet(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
return TagData(e,sheet);
}
function doPost(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
return TagData(e,sheet);
}
function TagData(e) {
var Location = e.parameter.Location; // send from app with respective tag
var sectiontSelect = e.parameter.sectiontSelect; // send from app with respective tag
sheet.append([Location, sectiontSelect])
}
function FilterOnText() {
var ss = SpreadsheetApp.getActive()
var range = ss.getDataRange();
var filter = range.getFilter() || range.createFilter()
var text = SpreadsheetApp.newFilterCriteria().whenTextContains(Location); // the location will be as per the location variable in the TagData function
filter.setColumnFilterCriteria(1, text);
}
function titleAsDate() {
const currentDate = Utilities.formatDate(new Date(), "GMT+4", "dd-MM-yyyy HH:mm:ss");
return SpreadsheetApp.create("Report of the " + currentDate);
}
function copyWithValues() {
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = spreadSheet.getSheetByName(sectionSelect); // fromApp variable will define which sheet the data will be copied (situated in the TagData function)
const temp_sheet = spreadSheet.insertSheet('temp_sheet');
const sourceRange = sourceSheet.getFilter().getRange();
sourceRange.copyTo(
temp_sheet.getRange('A1'),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL,
false);
SpreadsheetApp.flush();
const sourceValues = temp_sheet.getDataRange().getValues();
const targetSpreadsheet = titleAsDate();
const rowCount = sourceValues.length;
const columnCount = sourceValues[0].length;
const targetSheet = targetSpreadsheet.getSheetByName('Sheet1').setName("Report"); // renamed sheet
const targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
spreadSheet.deleteSheet(temp_sheet);
}
function MoveFiles(){
var files = DriveApp.getRootFolder().getFiles();
var file = files.next();
var destination = DriveApp.getFolderById("1wan7PLhl4UFEoznmsN_BVa2y4AtFaCOr");
destination.addFile(file)
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
function clearFilter() { // clearance of filters applied in first function
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("testo");
sheet.getFilter().remove();
}
Explanation:
Two issues:
TagData does not return anything (as Cooper pointed out)
TagData(e) has only one parameter e but you are passing two parameters TagData(e,sheet) when you call it from the doGet and doPost functions.
Not sure if this will solve all your issues, but it will solve the ones I mentioned above.
Solution:
Remove the return statements from doGet and doPost because of issue 1).
Add the sheet parameter in the TagData function.
Resulting code:
function doGet(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
TagData(e,sheet); // modified
}
function doPost(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
TagData(e,sheet); // modified
}
// added the sheet parameter
function TagData(e,sheet) {
var Location = e.parameter.Location; // send from app with respective tag
var sectiontSelect = e.parameter.sectiontSelect; // send from app with respective tag
sheet.append([Location, sectiontSelect]);
}
// rest of your code..
Or try this:
function doGet(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
var params = JSON.stringify(TagData(e,sheet)); // modified
return HtmlService.createHtmlOutput(params); // added
}
function doPost(e) {
var ss = SpreadsheetApp.openByUrl("sheetURL")
var sheet = ss.getSheetByName(Location);
ContentService.createTextOutput(JSON.stringify(e))
}
// added the sheet parameter
function TagData(e,sheet) {
var Location = e.parameter.Location; // send from app with respective tag
var sectiontSelect = e.parameter.sectiontSelect; // send from app with respective tag
sheet.append([Location, sectiontSelect]);
return { Location: Location, sectiontSelect: sectiontSelect }
}

Google sheets OCR image at URL in Col1, output text in Col2?

in a Google Sheet, I'm trying to use a function to OCR an image whose URL is in column A, and output the OCR text in column B. The code I'm attempting to use is from this thread:
ocr images from list of urls and store the results in spreadsheet
function onOpen() {
var ss = SpreadsheetApp.getActive();
var menuItems = [
{name: 'RUN', functionName: 'doGet2'}
];
ss.addMenu('OCR', menuItems);
}
function doGet2() {
var ROW_START = 3;
var URL_COL = 1;
var TEXT_COL = 2;
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var urls = sheet.getRange(ROW_START,URL_COL, sheet.getLastRow()-ROW_START+1,1).getValues();
var texts = [];
for(var i=0; i<urls.length; i++) {
var url = urls[i];
if(url != undefined && url != "") {
var imageBlob = UrlFetchApp.fetch(url).getBlob();
var resource = {
title: imageBlob.getName(),
mimeType: imageBlob.getContentType()
};
var options = {
ocr: true
};
var docFile = Drive.Files.insert(resource, imageBlob, options);
var doc = DocumentApp.openById(docFile.id);
var text = doc.getBody().getText().replace("\n", "");
texts.push([text]);
Drive.Files.remove(docFile.id);
}
else {
texts.push("request error");
}
}
sheet.getRange(ROW_START,TEXT_COL, urls.length,1).setValues(texts);
}
Here is the Google Sheet I'm testing with. Anyone can edit:
https://docs.google.com/spreadsheets/d/1jhSmE295bTOzjoXmgcyymNi-6ylKg5PLEKktPZJTD1c/edit?usp=sharing
I think the original code is meant to pull from Google Drive. I don't need that, I just want to pull from a URL. Being able to use the function inside an arrayformula would be a plus.
Thanks!

How to get e.parameter.array() in doGet(e) funtion in Google app script while submitting an array via HTML Form

I am trying to submit Html form with an array to google app script webapp but unable to retrieve array into the app.
here the html form code
function onOpen(){
SpreadsheetApp.getUi().createMenu("Send Mail").addItem("Insurance Mail", "insuranceMail").addToUi();
}
function insuranceMail(){
var webApp = "https://script.google.com/macros/s/AKfycbwsAlL2GWySwmkGooucVmDXTJK60TLAcAgQWYAdxGumgdI2Kjs/exec";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var row = sh.getActiveRange().getRow();
var clientName = sh.getRange("A"+row).getDisplayValue();
var senderID = Session.getActiveUser().getEmail();
var clientID = sh.getRange("B"+row).getDisplayValue();
var senderName = sh.getRange("C"+row).getDisplayValue();
var namesOfIns = sh.getRange("D"+row).getDisplayValue().replace(/,/g,"<br>"); //Next Line Formatting
var sub= "Additional Credentialing Options";
var message = "";
var date = new Date();
var iSheet = ss.getSheetByName("Insurances");
var iLastRow = iSheet.getLastRow();
var insurances = [];
var plan = [];
var values = [];
var tableRows = [];
var j,count = 1,tableRow;
for(var i = 0;i<=iLastRow;i++){
j=i+2;
insurances[i] = iSheet.getRange("A"+j).getDisplayValue(); //Get Insurance Names
}
for(var i = 0;i<=iLastRow;i++){
j=i+2;
plan[i] = iSheet.getRange("B"+j).getDisplayValue(); //Get Plan Names
}
for(var i = 0;i<=iLastRow;i++){
j=i+2;
values[i] = iSheet.getRange("C"+j).getDisplayValue(); // Get Yes/No values
}
var messageHtmlTop = "<!DOCTYPE html><html><head>"
+"<style> table{font-size:11px;font-family:sans-serif;} tr,td {padding: 0px 0px 0px 0px;text-align:center;}</style></head>"
+"<body>"
+"Hello "+clientName+",<br><br>"
+"<br><br>"
+"Some Html"
+"<b>"+namesOfIns+"</b><br><br>";
var messageHtmlTop2 = "<form action ='"+webApp+"'method='GET'><input type='email' name='clientID' value='"+clientID+"' style='display: none'><input type='text' name='clientName' value='"+clientName+"' style='display: none'>"
+"<table><tr><th>Sr. No.</th><th>Select</th><th>Insurance</th><th>Plane</th></tr>";
var messageHtmlMid = "";
for(n in insurances){
if(values[n] == "Yes" || values[n] == "yes"){
tableRow ="<tr>"
+"<td>"+count+"</td>"
+"<td><input type='checkbox' name='insurances[]' value='"+insurances[n]+"'></td>"
+"<td>"+insurances[n]+"</td>"
+"<td>"+plan[n]+"</td>"
+"</tr>";
tableRows[n] = tableRow;
count++;
} // Creat table rows array
} //Add Form top to the HTML on if atleast 1 Yes is present
for(n in tableRows){
messageHtmlMid = messageHtmlMid.concat(tableRows[n]); //Compose HTML Form Mid Part
};
var messageHtmlBottom1 ="<tr></tr><tr><td></td><td></td><td><input type='submit' value='Send' width=100% hieght=40px></td></tr></table>"
+"</form><br><br>"
+"some sentence<br><br>"
var messageHtmlBottom ="some HTML"
+"</body>"
+"</html>";
for(n in values){
if (values[n] == 'Yes'){
messageHtmlTop = messageHtmlTop.concat(messageHtmlTop2);
messageHtmlBottom = messageHtmlBottom1.concat(messageHtmlBottom);
break;
}
} ////Add Form bottom to the HTML on if atleast 1 Yes is present
var messageHtml = messageHtmlTop.concat(messageHtmlMid).concat(messageHtmlBottom); //Compose Full HTML with Form
Logger.log(messageHtml);
try{
MailApp.sendEmail(clientID,sub,message,{'htmlBody':messageHtml});
sh.getRange("E"+row).setValue("Sent");
} catch(e){
sh.getRange("E"+row).setValue("Error");
}
sh.getRange("F"+row).setValue(date);
}
Here my webapp code i am trying to work which is giving me empty result.
function doGet(e) {
var name = e.parameter.clientName;
var id = e.parameter.clientID;
var date = new Date();
var iSheet = SpreadsheetApp.openById("ID").getSheetByName("Responses");
var lastRow = iSheet.getLastRow();
var getIns =[];
var insurances = "";
for(n in e.parameter.insurances){
getIns[n] = e.parameter.insurances[n];
}
for(n in getIns){
insurances = insurances.concat(getIns[n]+"\n");
}
lastRow++;
iSheet.getRange("A"+lastRow).setValue(name);
iSheet.getRange("B"+lastRow).setValue(id);
iSheet.getRange("C"+lastRow).setValue(insurances);
iSheet.getRange("D"+lastRow).setValue(date);
return ContentService.createTextOutput('Some Sentence').setMimeType(ContentService.MimeType.TEXT)
}
I am getting client name,client ID,date printed into the sheet but the Column C is coming empty
There are two reasons you get an empty entry into the spreadsheet.
In the form, checkboxes are named as insurances[]. However, in the web app you refer to them as just insurances. So, please modify your Html so that the checkboxes are named 'insurances'
+"<td><input type='checkbox' name='insurances' value='"+insurances[n]+"'></td>"
As mentioned in the documentation here . The e.parameter only retrieves the first key:value pair
An object of key/value pairs that correspond to the request parameters. Only the first value is returned for parameters that have multiple values.
Instead, use e.parameters. Note the 's' at the end, it will return an array of checkbox values that were checked. As mentioned in the documentation above.
So instead of the following:
for(n in e.parameter.insurances){
getIns[n] = e.parameter.insurances[n];
}
for(n in getIns){
insurances = insurances.concat(getIns[n]+"\n");
}
you can just do this
var insurances = e.parameters.insurances.join("\n")
Your final web app would be the following:
function doGet(e) {
var name = e.parameter.clientName;
var id = e.parameter.clientID;
var date = new Date();
var iSheet = SpreadsheetApp.openById("ID").getSheetByName("Responses");
var lastRow = iSheet.getLastRow();
var getIns =[];
var insurances = e.parameters.insurances.join("\n")
lastRow++;
iSheet.getRange("A"+lastRow).setValue(name);
iSheet.getRange("B"+lastRow).setValue(id);
iSheet.getRange("C"+lastRow).setValue(insurances);
iSheet.getRange("D"+lastRow).setValue(date);
return ContentService.createTextOutput('We have received your request').setMimeType(ContentService.MimeType.TEXT)
}
Final note: Make sure to update your web app and redeploy.
References:
join()