The Idea:
User selects “Email” from menu which opens the Google Sidebar.
It prompts the user to select their field office location with radio buttons and add their additional message for the email body with a text area
User clicks Submits and “FFO_Email” function runs
“FFO_Email” function will do the following
Determines the Field Office Location based on the radio selection
Determines the list of emails based on Field Office Location ('FFO-IS'!A3:A12) and emails to the right in “FFO-IS” sheet ('FFO-IS'!B3:H12)
Creates email subject
Creates email body (which will incorporate the additional message from text area in sidebar
Finally sending email to individuals and displaying the message the email has been sent successfully in the sidebar
The problems I’m having
The selected radio Field Office Location and Additional Message are not passing to the FFO_Email.gs function. Thus not sending the email to the individuals.
Sheet can be found here
https://docs.google.com/a/cougars.ccis.edu/spreadsheets/d/1PK18AXMlfC2reKRP7IJWHRT9TEnDzfWa3g-uavgsxUk/edit?usp=sharing
FFO_email.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(fieldOffice, AdditionalMessage) {
var div = document.getElementById('fieldOfficeFFO');
div.innerHTML = 'Email for ' + fieldOffice + ' has been sent successfully.';
}
google.script.run.withSuccessHandler(onSuccess)
.FFO_Email();
</script>
</head>
<body>
<form id=fieldOfficeFFO>
<fieldset style="background-color:LightGray;width:250px">
<div>
<label for="Field Office Select">Please select your field office below.</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="ARK_E_TEXAS">
<label for="ARK_E_TEXAS">ARK_E_TEXAS</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="BORDER_EAST">
<label for="BORDER_EAST">BORDER_EAST</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="BORDER_WEST">
<label for="BORDER_WEST">BORDER_WEST</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="CENTRAL_TEXAS">
<label for="CENTRAL_TEXAS">CENTRAL_TEXAS</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="DALLAS">
<label for="DALLAS">DALLAS</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="FORT_WORTH">
<label for="FORT_WORTH">FORT_WORTH</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="GULF_COAST">
<label for="GULF_COAST">GULF_COAST</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="LOUISIANA">
<label for="LOUISIANA">LOUISIANA</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="NEW_MEXICO">
<label for="NEW_MEXICO">NEW_MEXICO</label>
</div>
<div>
<input type="radio" name="fieldOfficeFFO" id="fieldOfficeFFO" value="OKLAHOMA">
<label for="OKLAHOMA">OKLAHOMA</label>
</div>
</fieldset>
<br>
<br>
<fieldset>
<div class="form-group">
<label for="AdditionalMessage">Additional Message</label>
<textarea id="AdditionalMessage" rows="3" style="width:250px"></textarea>
</div>
</fieldset>
</form>
<div class="block">
<button class="blue" onclick="onSuccess(fieldOfficeFFO,AdditionalMessage)">Submit</button>
<button onclick="google.script.host.close()">Close</button>
</div>
</body>
</html>
FFO_Email.gs
function FFO_Email(fieldOfficeFFO, AdditionalMessage) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FFO-IS')
var firstRow = 3;
var lastRow = 10;
var dataRange = sheet.getRange(firstRow, 1, lastRow, 8);
var myDate = new Date();
var hrs = myDate.getHours();
//Determines the row the Field Office is in
for (var j = 0; j < dataRange.length; j++) {
if (dataRange[j][0] == fieldOfficeFFO) {
Logger.log((j + 1))
return j + 1;
}
}
//Create the greeting based on the time of day
var greeting;
if (hrs < 12)
greeting = 'Good Morning';
else if (hrs >= 12 && hrs <= 17)
greeting = 'Good Afternoon';
else if (hrs >= 17 && hrs <= 24)
greeting = 'Good Evening';
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var field_Office = fieldOfficeFFO;
var PT_Director = dataRange.getValues(j, 2);
var PT_Manager = dataRange.getValues(j, 3);
var PT_Management_Specialist = dataRange.getValues(j, 4);
var Area_Supervisory_AM = dataRange.getValues(j, 5);
var Area_AM = dataRange.getValues(j, 6);
var SC_Senior_Property_Manager = dataRange.getValues(j, 7);
var AMS = dataRange.getValues(j, 8);
var email_Subject = field_Office + " FFO / Income Statement Report is ready for viewing";
var message_Body = greeting + "," +
"<br> <br>" +
"The " + field_Office + " <b>FFO / Income Statement Report is ready for viewing in</b> the <i>AMS Standard Reports - R07 Google Folder</i>" +
" located at https://drive.google.com/drive/u/0/folders/0Bx1aKS2V9K-kb0tNLXFfbGtmalE" +
"<br> <br>" +
"<br> <br>" +
//Additional Message from html side added here
AdditionalMessage +
"<br> <br>" +
"Thank you." +
"<br> <br>" +
AMS;
//Send email
MailApp.sendEmail({
to: SC_Senior_Property_Manager + "," + Area_AM + "," + AMS,
cc: PT_Director + "," + PT_Manager + "," + PT_Management_Specialist + "," + Area_Supervisory_AM,
replyTo: AMS,
subject: email_Subject,
htmlBody: message_Body
});
return fieldOfficeFFO
SpreadsheetApp.flush();
Utilities.sleep(1000);
}
}
Radio inputs in the same group can't have the same id=.
Giving them the same name attribute is ok if that's how you want to group them.
Textarea has no name= attribute at all.
There are quite a few changes that need to be made:
I'd create a new function for the submission, I'm calling it sendInputInfo():
Script Tag:
<script>
function sendInputInfo() {
console.log('sendInputInfo ran!');//Open browsers console to see print out
//Get the form information to be sent
var theFormElement = document.getElementById('fieldOfficeFFO');
google.script.run.withSuccessHandler(onSuccess)
.FFO_Email(theFormElement);
};
function onSuccess(fieldOffice, AdditionalMessage) {
div.innerHTML = 'Email for ' + fieldOffice + ' has been sent successfully.';
};
</script>
Change the onclick attribute:
<button class="blue" onclick="sendInputInfo()">Submit</button>
Note that there are no values in the parenthesis being sent to the function. That's not needed. The form is being retrieved in the sendInputInfo() function.
Currently, the code is not passing any information to the server. There is nothing in the parenthesis of the server function:
Currently:
.FFO_Email();
There needs to be something in the parenthesis:
.FFO_Email(theFormElement);
Your .gs code has two arguments in the parenthesis. Apps Script will only accept one input on the server side if it is a form object. So, you'll need to change the function to:
function FFO_Email(theFormObject) {
Logger.log('theFormObject: ' + theFormObject);//Should be an object
Logger.log('theFormObject.fieldOfficeFFO: ' + theFormObject.fieldOfficeFFO);
for (var key in theFormObject) {//Loop through all the data in the form
Logger.log('key: ' + key);
Logger.log('value: ' + theFormObject[key]);
};
Related
This is my first post and I have searched for days and can not find a solution for this problem.
I have a custom menu in sheets that pops up a .showModalDialog html. A user fills that out with information and clicks submit. This runs a function in the back end that creates folders/files and adds the user data to various sheets etc.
All this is working I have a Ui.alert that I am using to check the data entered is correct and for some reason the function is being trigger twice and the UI.alert is popping up again as a result. I have a fail safe that checks if one of the fields exists so it doesn't write again but the pop up is a really bad user experience.
Any help would be much appreciated.
Function to create custom menu:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('TOA - Menu')
.addItem('Add New Account', 'addAccount')
.addItem('Update Brand', 'updateBrand')
.addItem('Go Live', 'goLive')
.addToUi();
}
Function to bring up form:
function addAccount() {
const html = HtmlService.createHtmlOutputFromFile('newAccount')
.setTitle('Add New Account')
.setWidth(1000)
.setHeight(800);;
SpreadsheetApp.getUi()
.showModalDialog(html, 'Add New Account');
}
Code for the form:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
#itemDisplay {
display: none;
}
#modDisplay {
display: none;
}
#priceDisplay {
display: none;
}
#businessTypeDisplay {
display: none;
}
</style>
</head>
<body>
<h1>
Add New Account
</h1>
<form id="myForm" onsubmit="handleNewAccountFormSubmit(this);">
<div>
<label for="newBrand">Brand:</label>
<input name="newBrand" type="text" placeholder="Brand Name" required>
</div>
<div>
<p>Location</p>
<label for="country">Country:</label>
<select name="country" id="" onchange="" required>
<option value="" disabled selected>Select Country</option>
<option value="US">US</option>
</select>
<label for="state">State/Province:</label>
<input name="state" type="text" placeholder="State or province" required>
<label for="city">City:</label>
<input name="city" type="text" placeholder="City" required>
<div>
<label for="businessType">Business Type:</label>
<select name="businessType" id="businessTypeSelect" onchange="businessOtherDisplay(this.value);" required>
<option value="" disabled selected>Select Request Reason</option>
<option value="americanDiner">American Diner</option>
<option value="pizzaParlor">Pizza Parlor</option>
<option value="coffeeShop">Coffee Shop</option>
<option value="candyShop">Candy Store</option>
<option value="iceCreamParlor">Ice Cream Parlor</option>
<option value="burgerShop">Burger Shop</option>
<option value="otherNon_AmericanDiner">Other non-American Diner (Foreign servings)</option>
<option value="other">Other (not listed above)</option>
</select>
</div>
<div id="businessTypeDisplay">
<label for="businessTypeOther">Business Type Other:</label>
<input name="businessTypeOther" type="text" placeholder="Business type if not listed above">
</div>
<div>
<label for="integration">Integration:</label>
<select name="integration" required>
<option value="" disabled selected>Select Request Reason</option>
<option value="square">Square</option>
<option value="clover">Clover</option>
<option value="cloverPilot">Clover Pilot</option>
<option value="stripe">Stripe</option>
<option value="gPay">GPAY</option>
<option value="others" >Others</option>
</select>
</div>
<label for="menuSource">File Attachment/Source:</label>
<input name="menuSource" type="text" placeholder="Path to menu" required url>
<div>
<p>Do you need an item hidden/disabled?</p>
<label for="yes">Yes</label>
<input name="disableItemOption" type="radio" value="yes" onclick="showItem()">
<label for="no">No</label>
<input name="disableItemOption" type="radio" value="no" checked onclick="hideItem()">
</div>
<div id="itemDisplay">
<label for="itemDisable">Which item(s) should be disabled?</label>
<textarea id="disabledItem" name="itemDisable" cols="40" rows="5"></textarea>
</div>
<div>
<p>Do you need a modifier hidden/disabled?</p>
<label for="yes">Yes</label>
<input name="disableModOption" type="radio" value="yes" onclick="showMod()">
<label for="no">No</label>
<input name="disableModOption" type="radio" value="no" checked onclick="hideMod()">
</div>
<div id="modDisplay">
<label for="modDisable">Which modifier(s) should be disbaled?</label>
<textarea id="disabledMod" name="modDisable" cols="40" rows="5"></textarea>
</div>
<div>
<p>Do you need to update a price?</p>
<label for="yes">Yes</label>
<input name="updatePrice" type="radio" value="yes" onclick="showPrice()">
<label for="no">No</label>
<input name="updatePrice" type="radio" value="no" checked onclick="hidePrice()">
</div>
<div id="priceDisplay">
<label for="priceUpdate">Which item/modifier needs a price update?</label>
<textarea id="updatedPrice" name="priceUpdate" cols="40" rows="5" priceUpdate></textarea>
</div>
<div>
<label for="otherUpdates">Any other information needed on the menu?</label>
<input name="otherUpdates" type="text" placeholder="List other instructions here">
</div>
<div>
<label for="specialInstructions">Are there special instructions/notes for this brand?</label>
<input name="specialInstructions" type="text" placeholder="List special instructions here">
</div>
<input id="submitButton" type="submit" value="Submit">
<input type="button" value="Cancel" onclick="google.script.host.close()">
</div>
</form>
<script>
function handleNewAccountFormSubmit(formObject) {
document.getElementById('submitButton').disabled=true;
google.script.run.withSuccessHandler().processNewAccountForm(formObject);
}
function disableSubmit() {
document.getElementById('submitButton').disabled=true;
document.getElementById('submitButton').value='Sending...';
}
function showItem(){
document.getElementById('itemDisplay').style.display ='block';
document.getElementById('disabledItem').required = true;
};
function hideItem(){
document.getElementById('itemDisplay').style.display = 'none';
document.getElementById('disabledItem').required = false;
};
function showMod(){
document.getElementById('modDisplay').style.display ='block';
document.getElementById('disabledMod').required = true;
};
function hideMod(){
document.getElementById('modDisplay').style.display = 'none';
document.getElementById('disabledMod').required = false;
};
function showPrice(){
document.getElementById('priceDisplay').style.display ='block';
document.getElementById('updatedPrice').required = true;
};
function hidePrice(){
document.getElementById('priceDisplay').style.display = 'none';
document.getElementById('updatedPrice').required = false;
};
function businessOtherDisplay(value) {
if(value === "other") {
document.getElementById('businessTypeDisplay').style.display = 'block';
} else {
document.getElementById('businessTypeDisplay').style.display = 'none';
};
};
</script>
</body>
</html>
And the code to handle the logic
function processNewAccountForm(formObject) {
const ui = SpreadsheetApp.getUi();
const ass = SpreadsheetApp.getActiveSpreadsheet();
const ss = ass.getActiveSheet();
const timestamp = Utilities.formatDate(new Date(), "GMT+8", "MM/dd/yyyy HH:mm:ss");
const userEmail = Session.getActiveUser().getEmail();
const brandName = formObject.newBrand;
// Add alert to check data entered is correct
const response = ui.alert('Please confirm the following information is correct:',
'𝗕𝗿𝗮𝗻𝗱 𝗡𝗮𝗺𝗲: ' + formObject.newBrand +
'\n𝗖𝗼𝘂𝗻𝘁𝗿𝘆: ' + formObject.country +
'\n𝗦𝘁𝗮𝘁𝗲: ' + formObject.state +
'\n𝗖𝗶𝘁𝘆: ' + formObject.city +
'\n𝗕𝘂𝘀𝗶𝗻𝗲𝘀𝘀 𝗧𝘆𝗽𝗲: ' + formObject.businessType +
'\n𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻: ' + formObject.integration +
'\n𝗙𝗶𝗹𝗲 𝗦𝗼𝘂𝗿𝗰𝗲: ' + formObject.menuSource +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝗮𝗻 𝗶𝘁𝗲𝗺 𝗵𝗶𝗱𝗱𝗲𝗻/𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.disableItemOption +
'\n𝗪𝗵𝗶𝗰𝗵 𝗶𝘁𝗲𝗺(𝘀) 𝘀𝗵𝗼𝘂𝗹𝗱 𝗯𝗲 𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.itemDisable +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝗮 𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿 𝗵𝗶𝗱𝗱𝗲𝗻/𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.disableModOption +
'\n𝗪𝗵𝗶𝗰𝗵 𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿𝘀 𝘀𝗵𝗼𝘂𝗹𝗱 𝗯𝗲 𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.modDisable +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝘁𝗼 𝘂𝗽𝗱𝗮𝘁𝗲 𝗮 𝗽𝗿𝗶𝗰𝗲?: ' + formObject.updatePrice +
'\n𝗪𝗵𝗶𝗰𝗵 𝗶𝘁𝗲𝗺/𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿 𝗻𝗲𝗲𝗱𝘀 𝗮 𝗽𝗿𝗶𝗰𝗲 𝘂𝗽𝗱𝗮𝘁𝗲?: ' + formObject.priceUpdate +
'\n𝗔𝗻𝘆 𝗼𝘁𝗵𝗲𝗿 𝗶𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻 𝗻𝗲𝗲𝗱𝗲𝗱 𝗼𝗻 𝘁𝗵𝗲 𝗺𝗲𝗻𝘂?: ' + formObject.otherUpdates +
'\n𝗔𝗿𝗲 𝘁𝗵𝗲𝗿𝗲 𝘀𝗽𝗲𝗰𝗶𝗮𝗹 𝗶𝗻𝘀𝘁𝗿𝘂𝗰𝘁𝗶𝗼𝗻𝘀/𝗻𝗼𝘁𝗲𝘀 𝗳𝗼𝗿 𝘁𝗵𝗶𝘀 𝗯𝗿𝗮𝗻𝗱?: ' + formObject.specialInstructions
, ui.ButtonSet.YES_NO);
if(response === ui.Button.YES) {
var lock = LockService.getScriptLock();
lock.waitLock(60000);
try {
const brandColumn = ss.getRange('D:D');
const brandValues = brandColumn.getValues();
let i = 1;
// Check for exisiting brand name
for(i=1; i < brandValues.length; i++) {
if(brandValues[i].toString().toLowerCase().trim() == brandName.toString().toLowerCase().trim() && ss.getRange(i+1,5).getValue() == 'New Brand'){
ui.alert("Brand name already created");
return;
}
};
// Create folder and PDF with build instructions
const parentFolder = DriveApp.getFolderById("RemovedfolderID");// how does this work with Shared drives? Create and move?
// const parentFolder = DriveApp.getFolderById("RemovedfolderID"); < ---- Team drive ID (notworking..) My folder -> RemovedfolderID
const newFolder = parentFolder.createFolder(brandName);
const docFile = newFolder.createFile(brandName+'.pdf',
'𝗕𝗿𝗮𝗻𝗱 𝗡𝗮𝗺𝗲: ' + formObject.newBrand +
'\n𝗖𝗼𝘂𝗻𝘁𝗿𝘆: ' + formObject.country +
'\n𝗦𝘁𝗮𝘁𝗲: ' + formObject.state +
'\n𝗖𝗶𝘁𝘆: ' + formObject.city +
'\n𝗕𝘂𝘀𝗶𝗻𝗲𝘀𝘀 𝗧𝘆𝗽𝗲: ' + formObject.businessType +
'\n𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻: ' + formObject.integration +
'\n𝗙𝗶𝗹𝗲 𝗦𝗼𝘂𝗿𝗰𝗲: ' + formObject.menuSource +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝗮𝗻 𝗶𝘁𝗲𝗺 𝗵𝗶𝗱𝗱𝗲𝗻/𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.disableItemOption +
'\n𝗪𝗵𝗶𝗰𝗵 𝗶𝘁𝗲𝗺(𝘀) 𝘀𝗵𝗼𝘂𝗹𝗱 𝗯𝗲 𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.itemDisable +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝗮 𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿 𝗵𝗶𝗱𝗱𝗲𝗻/𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.disableModOption +
'\n𝗪𝗵𝗶𝗰𝗵 𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿𝘀 𝘀𝗵𝗼𝘂𝗹𝗱 𝗯𝗲 𝗱𝗶𝘀𝗮𝗯𝗹𝗲𝗱?: ' + formObject.modDisable +
'\n𝗗𝗼 𝘆𝗼𝘂 𝗻𝗲𝗲𝗱 𝘁𝗼 𝘂𝗽𝗱𝗮𝘁𝗲 𝗮 𝗽𝗿𝗶𝗰𝗲?: ' + formObject.updatePrice +
'\n𝗪𝗵𝗶𝗰𝗵 𝗶𝘁𝗲𝗺/𝗺𝗼𝗱𝗶𝗳𝗶𝗲𝗿 𝗻𝗲𝗲𝗱𝘀 𝗮 𝗽𝗿𝗶𝗰𝗲 𝘂𝗽𝗱𝗮𝘁𝗲?: ' + formObject.priceUpdate +
'\n𝗔𝗻𝘆 𝗼𝘁𝗵𝗲𝗿 𝗶𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻 𝗻𝗲𝗲𝗱𝗲𝗱 𝗼𝗻 𝘁𝗵𝗲 𝗺𝗲𝗻𝘂?: ' + formObject.otherUpdates +
'\n𝗔𝗿𝗲 𝘁𝗵𝗲𝗿𝗲 𝘀𝗽𝗲𝗰𝗶𝗮𝗹 𝗶𝗻𝘀𝘁𝗿𝘂𝗰𝘁𝗶𝗼𝗻𝘀/𝗻𝗼𝘁𝗲𝘀 𝗳𝗼𝗿 𝘁𝗵𝗶𝘀 𝗯𝗿𝗮𝗻𝗱?: ' + formObject.specialInstructions,
MimeType.PDF);
const fileURL = docFile.getUrl();
// add header row to spreadsheet
// Create Spreadsheet in Brand folder. Activity log.
const name = brandName + " Activity Log";
const id = newFolder.getId();
const resource = {
title: name,
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{id: id}]
};
const fileJson = Drive.Files.insert(resource);
const fileId = fileJson.id;
const lastRow = ss.getLastRow();
const newEntry = [
lastRow,
timestamp,
timestamp,
formObject.newBrand,
'New Brand',
formObject.businessType,
formObject.integration,
'=HYPERLINK("'+formObject.menuSource+'")',
userEmail,
fileURL,
,
,
,
,
formObject.city,
formObject.state,
formObject.country,
fileId
];
const newSheet = SpreadsheetApp.openById(fileId);
const sheetRange = newSheet.getSheetByName("Sheet1").getRange(1,1,1,18);
const headers = [
['𝗜𝗻𝗱𝗲𝘅',
'𝗕𝗿𝗮𝗻𝗱 𝗼𝗿𝗶𝗴𝗶𝗻𝗮𝗹 𝗰𝗿𝗲𝗮𝘁𝗲 𝗱𝗮𝘁𝗲',
'𝗧𝗶𝗺𝗲 𝗜𝗻',
'𝗕𝗿𝗮𝗻𝗱 𝗡𝗮𝗺𝗲',
'𝗥𝗲𝗾𝘂𝗲𝘀𝘁 𝗿𝗲𝗮𝘀𝗼𝗻',
'𝗕𝘂𝘀𝗶𝗻𝗲𝘀𝘀 𝘁𝘆𝗽𝗲',
'𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻',
'𝗠𝗲𝗻𝘂 𝗦𝗼𝘂𝗿𝗰𝗲',
'𝗖𝗿𝗲𝗮𝘁𝗲𝗱 𝗯𝘆:',
'𝗠𝗲𝗻𝘂 𝗜𝗻𝘀𝘁𝗿𝘂𝗰𝘁𝗶𝗼𝗻𝘀',
'𝗔𝘀𝘀𝗶𝗴𝗻𝗲𝗱 𝘁𝗼?',
'𝗧𝗶𝗺𝗲 𝗢𝘂𝘁',
'𝗖𝗼𝗺𝗽𝗹𝗲𝘅𝗶𝘁𝘆 𝗥𝗮𝘁𝗶𝗻𝗴',
'𝗚𝗼 𝗹𝗶𝘃𝗲 𝗱𝗮𝘁𝗲 𝗮𝗻𝗱 𝘁𝗶𝗺𝗲',
'𝗖𝗶𝘁𝘆',
'𝗦𝘁𝗮𝘁𝗲/𝗣𝗿𝗼𝘃𝗶𝗻𝗰𝗲',
'𝗖𝗼𝘂𝗻𝘁𝗿𝘆',
'𝗔𝗰𝘁𝗶𝘃𝗶𝘁𝘆 𝗟𝗼𝗴']
];
sheetRange.setValues(headers);
// Add data to last row in main tracker
ss.appendRow(newEntry);
// Copy data to spreadsheet brand
const activitySheet = newSheet.getSheetByName("Sheet1")
activitySheet.appendRow(newEntry);
// Flush changes before releasing lock
SpreadsheetApp.flush();
} catch(e) {
ui.alert("System is Busy, Please try again in a moment.");
return
} finally {
lock.releaseLock();
return
}
} else {
// action to take if info is incorrect? or No is clicked
};
};
I know that multiple triggers have been a known issue as per posts from Cooper and others here and here but I can't seem to be able to adopt them for my solution.
Thanks in advance for any ideas.
These are the changes I'd make to the dialog:
<input id="btn1" type="button" value="Submit" onClick="handleNewAccountFormSubmit(this.parentNode);" />
<input type="button" value="Cancel" onclick="google.script.host.close()">
</div>
</form>
<script>
function handleNewAccountFormSubmit(formObject) {
document.getElementById('btn1').disabled=true;
google.script.run.processNewAccountForm(formObject);
}
I'm not saying that your way is wrong. That's just the way I would try to do it. But realistically it's a fairly large dialog and your just going to have to dig in and figure it out. If I were doing it and I was having a lot of problems I'd probably start with a simpler version and get it to work and then slowly add more features.
This is actually a fairly difficult time two write code in the middle of a transition between two runtimes. I've just noticed that I've lost my content assist in some areas in ES5 but they now work in ES6 so things can be difficult to deal with.
JavaScript:
function validateForm(){
var getNoun = document.formPG.fNoun.value;
var getVerb = document.formPG.fVerb.value;
var getPronoun = document.formPG.fPronoun.value;
var getAdverb = document.formPG.fAdverb.value;
var getAdjective = document.formPG.fAdjective.value;
var getSillyWord = document.formPG.fSillyWord.value;
var getMagic = document.formPG.fMagic.value;
if((getNoun) === ""){
alert("You entered a number value, please enter a Noun.");
document.formPG.fNoun.focus();
document.getElementById('iNoun').style.borderColor = "red";
return false;
}
//write story to [document].html
paragraph = "There was once a " + getAdjective + " magician who roamed the wild terrains of " + getAdverb + ".<br>";
paragraph += "The magician " + getNoun + " cast the mighty spell " + getMagic + " around the " + getSillyWord + ".<br>" + getPronoun + " knew there was only one way to win the war - " + getVerb + ".";
document.write(paragraph);
}
HTML:
<body>
<div class="container">
<h1>Mad Lib</h1>
<form name="formPG" onsubmit="validateForm()" method="post">
Noun: <input type="text" name="fNoun" id="iNoun"><br>
Pronoun: <input type="text" name="fPronoun" id="iPronoun"><br>
Verb: <input type="text" name="fVerb" id="iVerb"><br>
Adverb: <input type="text" name="fAdverb" id="iAdverb"><br>
Adjective: <input type="text" name="fAdjective" id="iAdjective"><br>
Silly Word: <input type="text" name="fSillyWord" id=""iSillyWord"><br>
Magic Spell: <input type="text" name="fMagic" id="iMagic"><br>
<input type="submit" value="submit">
</form>
<br>
<script src="madLib_v2.js"></script>
</div>
</body>
The problem is whenever I hit the "submit" button the page hits the document.getElementById('iNoun').style.borderColor = "red"; and goes away. The page refreshes instantly and the box is only highlighted for a fraction of a second. I want it to stay there until the page is refreshed basically or until they get it correct.
Do with return validateForm() .Then only its prevent page refresh .
Remove the unwanted space and quotes in elements attributes.like id=""iSillyWord"-extra quotes and type="submit "-unwanted space
function validateForm() {
var getNoun = document.formPG.fNoun.value;
var getVerb = document.formPG.fVerb.value;
var getPronoun = document.formPG.fPronoun.value;
var getAdverb = document.formPG.fAdverb.value;
var getAdjective = document.formPG.fAdjective.value;
var getSillyWord = document.formPG.fSillyWord.value;
var getMagic = document.formPG.fMagic.value;
if ((getNoun) === "") {
alert("You entered a number value, please enter a Noun.");
document.formPG.fNoun.focus();
document.getElementById('iNoun').style.borderColor = "red";
return false;
}
//write story to [document].html
paragraph = "There was once a " + getAdjective + " magician who roamed the wild terrains of " + getAdverb + ".<br>";
paragraph += "The magician " + getNoun + " cast the mighty spell " + getMagic + " around the " + getSillyWord + ".<br>" + getPronoun + " knew there was only one way to win the war - " + getVerb + ".";
document.write(paragraph);
}
<body>
<div class="container">
<h1>Mad Lib</h1>
<form name="formPG" onsubmit="return validateForm()" method="post">
Noun: <input type="text" name="fNoun" id="iNoun"><br> Pronoun: <input type="text" name="fPronoun" id="iPronoun"><br> Verb: <input type="text" name="fVerb" id="iVerb"><br> Adverb: <input type="text" name="fAdverb" id="iAdverb"><br> Adjective:
<input type="text" name="fAdjective" id="iAdjective"><br> Silly Word: <input type="text" name="fSillyWord" id="iSillyWord">
<br> Magic Spell: <input type="text " name="fMagic" id="iMagic"><br>
<input type="submit" value="submit">
</form>
<br>
</div>
</body>
prevent the default behavior as the form is getting submitted. Once it is valid use ajax to submit the form
JS
function validateForm(e){
e.preventDefault();
// rest of the code
}
HTML
pass the event object to the function
onsubmit="validateForm(event)"
DEMO
I want to validate the dynamically added fields of the form(present in the templates/appname) in django. I am adding those fields with the help of the javascript (addInput.js - stored at a place mentioned as source in the script tag) which also has the logics for removing those fields as well as validating those fields values. But when I click send_invites button, it directs me again to app/register when I first want that it should go to the validateEmail() function if everything is fine then it should redirect to app/register.
var counter = 1;
var limit = 5;
function addInput(divName) {
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " Email Addresses");
} else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<p id = 'remove" + counter + "'>Email Address " + (counter + 1) + " : " + "<input type = 'text' name ='myInputs[]'></p>";
document.getElementById(divName).appendChild(newdiv);
counter++;
alert(counter + "add");
}
}
function removeInput(divName) {
if (counter == 1) {
alert("You have reached the limit of removing Email Addresses");
} else {
counter--;
var olddiv = document.getElementById("remove" + counter);
alert(counter + "remove");
olddiv.parentNode.removeChild(olddiv);
}
}
function validateEmail(divName) {
var emailFilter = /^([a-zA-Z0-9_.-])+#(([a-zA-Z0-9-]+.)+([a-zA-Z0-9]{2,4})+$/;
console.log("cmn");
alert("cmn");
for (i = 0; i < counter; i++) {
var email = $("#remove" + i).val();
alert(email);
// return true;
}
return true;
}
<div id="page-wrapper">
<div class="row">
<div class="col-lg-12">
<br>
<h1 class="page-header">
Send Invites
</h1>
<form method="POST" onsubmit="return validateEmail('dynamicInput')" action="/app/register/">
<div id="dynamicInput">
<p id='remove0'>Email Address 1 :
<input type="text" name="myInputs[]">
</p>
</div>
<br>
<br>
<input type="button" value="Add another Email Address" onClick="addInput('dynamicInput');">
<input type="button" value="Remove Email Address Field " onClick="removeInput('dynamicInput');">
<br>
<br>
<input type="submit" value="Send Invites">
<input type='hidden' name='csrfmiddlewaretoken' value='xyz' />
</form>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
</div>
<!-- /#page-wrapper -->
</div>
<!-- /#wrapper -->
</div>
<style>
a.active {
background-color: #eee;
}
</style>
But why is this not happening? other two javascript functions addInput and removeInput are working fine. Only validateEmail is not getting called, for which I am even calling alert and console.log but nothing is getting displayed. Please help. I am new to javascript.
Running the code, clicking the button, you get the following error in the console.
Uncaught SyntaxError: Invalid regular expression:
/^([a-zA-Z0-9_.-])+#(([a-zA-Z0-9-]+.)+([a-zA-Z0-9]{2,4})+$/:
Unterminated group
Looking at the code you have an extra (
/^([a-zA-Z0-9_.-])+#(([a-zA-Z0-9-]+.)+([a-zA-Z0-9]{2,4})+$/;
^
So you are either missing a closing ) or you have the extra (. My guess is you are missing a ) before the +. Look at wherever you found the reg exp and see what it should be.
I'm writing an app using web2py and I'm currently trying to make a form where the user can add/remove additional fields on the fly. I've got this working by using jQuery to add the addition fields to the DOM but the problem is only the hardcoded fields are being submitted (I am dumping form.vars at the top of the page to check). I have made sure the dynamic fields have unique names and I've been scouring the html for errors but have come up with nothing.
Here's my javascript:
$(document).ready(function(){
var wrapper = $("#formwrapper");
var addbutton = $("#addfield");
var removebutton = $('#removefield');
var x = 2;
$(addbutton).click(function(){
$(wrapper).append(
"<div id='extrareward"+ x +"'><h3>Reward " + x + "</h3>" +
"<label>Minimum amount to get reward: </label>" +
"<input name='min"+ x +"' type='text'><br>" +
"<label>Reward Description: </label>" +
"<textarea name='reward"+ x +"' rows='10' cols='40'></textarea></div>"
);
x++;
});
$(removebutton).click(function(){
if (x > 2) {
x--;
var id = '#extrareward' + x;
$(id).remove();
}
});
});
And here's the html form from the page source with one static and one dynamic block:
<form action="#" enctype="multipart/form-data" method="post">
<div id="formwrapper">
<label>Minimum amount to get reward: </label>
<input name="min1" type="text" value=""><br>
<label>Reward description: </label>
<textarea cols="40" name="reward1" rows="10"></textarea><br>
<div id="extrareward2">
<h3>Reward 2</h3>
<label>Minimum amount to get reward: </label>
<input name="min2" type="text"><br>
<label>Reward Description: </label>
<textarea name="reward2"></textarea>
</div>
</div>
<input id="submitbutton" type="submit">
<div style="display:none;">
<input name="_formkey" type="hidden" value="1e315a07-a035-4858-822c-614c962ebb98">
<input name="_formname" type="hidden" value="default">
</div>
</form>
and finally here is the code for the controller:
#auth.requires_login()
def create2():
form = FORM(DIV(LABEL('Minimum amount to get reward: '), INPUT(_name='min1', _type='text'), BR(),
LABEL('Reward description: '), TEXTAREA(_name='reward1'), BR(),
_id='formwrapper'),
INPUT(_id='submitbutton', _type='submit'))
if form.process(keepvalues=True).accepted:
session.flash = 'form accepted'
else:
session.flash = 'form rejected'
return dict(loginform=auth.login(),
rewardtiersform=form)
Might be that I'm just missing a silly error somewhere but I've been scratching my head for too long in this. Help much appreciated!
I've had trouble with these for a while, I can't figure out how to make the variable(seating) equal to either 'Balcony', 'Lower Area', Level One' or 'level Two'.
I have tried using .select, making some array that I failed on, .checked .
I need to be able to make the seating variable equal to one of the value according to what bit of the select menu they pick(I am using if statements)
I will add my html and Javascript below.
<div data-role="fieldcontain">
<label for="selectmenu" class="select">Preferred Seating:</label> <!-- Following drop down checkbox -->
<select name="selectmenu" id="selectmenu">
<option name="selectmenu" value="200" class="lowerLvl" id="lowerArea" >Lower Area($200)</option>
<option name="selectmenu" value="150" class="levelOne" selected="selected" id="levelOne">Level 1($150)</option>
<option name="selectmenu" value="100" class="levelTwo" id="levelTwo">Level 2($100)</option>
<option name="selectmenu" value="200" class="balcony" id="balcony">Balcony($200)</option>
</select>
</div>
<!--End of DropDownBoxes-->
<!--START OF CHECK BOXES-->
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Prefered night:</legend>
<input type="radio" name="checkbox1" id="checkbox1_0" class="custom" value="" checked="checked" /></option>
<label for="checkbox1_0">Thursday</label>
<br />
<input type="radio" name="checkbox1" id="checkbox1_1" class="custom" value="" />
<label for="checkbox1_1">Friday</label>
<br /><!--Break as on Example-->
<input type="radio" name="checkbox1" id="checkbox1_2" class="custom" value="" />
<label for="checkbox1_2">Saturday</label>
</fieldset><!-- Above are check boxes -->
</div>
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Subscribe to weekly newsletter: </legend>
<input type="checkbox" name="newletter" id="news" class="custom" value="" />
</fieldset>
</div>
<!--END OF CHECK BOXES-->
<!--Put a tick box here that asks for weekly mail-->
<button type="submit" value="Register" onClick="validateGalaOrder()"></button>
<p id="OrderInput"></p><!--USERS INPUT RETURNS TO THIS <P>-->
<p id="tktCost"></p>
<p id="orderErrorMsg"></p><!--INCORRECT INPUT MESSAGES RETURN TO THIS <P>-->
Below is my JavaScript.
Please note that some of the JavaScript is from other parts of html above the select menu.
At the moment I am getting the 'value' from the select menu(this is in the else statement under the variable cost)
function validateGalaOrder() {
var orderErrorMsg = "";
var OrderInput = "";
var ValidateOrderName = document.getElementById('txtOrderName').value;
var numTickets = document.getElementById('numTickets').value;
var Orderemail = document.getElementById('txtOrderEmail');
var filter = /*Email Symbol and letter Validator*/ /^([a-zA-Z0-9_.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; //This filters out the email input
var lowerLvl = document.getElementById('lowerArea').value;
var lvlOne = document.getElementById('levelOne').value;
var lvlTwo = document.getElementById('levelTwo').value;
var Balcony = document.getElementById('balcony').value;
var cost = '';
var seating = '';
var prefNight; //This will contain the prefered night and print it
var newsLetter; //Has details about if they have chosen the newsletter or not.
if (ValidateOrderName.length <= 2) {
orderErrorMsg += ("<b>-ERROR- Please enter a valid name with a length of at least 3 letters</b>");
document.getElementById('orderErrorMsg').innerHTML = orderErrorMsg;
document.getElementById('txtOrderName').value = ''; //will clear input field if false.
document.getElementById('txtOrderName').focus(); //this Focuses on textbox if input is wrong.
//alert("-ERROR- Please enter a name more than one letter!");
document.getElementById('OrderInput').innerHTML = ''; //If someone decides to change there input and that changed input is wrong then this will clear the other data from under the button and just show the error message
return false;
}
if (!filter.test(Orderemail.value)) {
orderErrorMsg += ("<b>-ERROR- Please provide a valid email address.</b>");
document.getElementById('orderErrorMsg').innerHTML = orderErrorMsg;
document.getElementById('txtOrderEmail').value = '';
document.getElementById('txtOrderEmail').focus(); //this Focuses on textbox if input is wrong.
// alert('Please provide a valid email address');
document.getElementById('OrderInput').innerHTML = ''; //If someone decides to change there input and that changed input is wrong then this will clear the other data from under the button and just show the error message
return false;
}
if (numTickets <= 0) {
orderErrorMsg += ("<b>-ERROR- Please enter an amount of tickets greater than zero</b>");
document.getElementById('orderErrorMsg').innerHTML = orderErrorMsg;
document.getElementById('numTickets').value = '';
document.getElementById('numTickets').focus(); //this Focuses on textbox if input is wrong.
/*alert("-ERROR- Please enter a mobile number with exactly 10 numeric digits");*/
document.getElementById('OrderInput').innerHTML = ''; //If someone decides to change there input and that changed input is wrong then this will clear the other data from under the button and just show the error message
return false;
} else {
if (document.getElementsById('lowerArea').checked == true) {
seating = "Lower Area";
}
if (document.getElementsById('levelOne').checked == true) {
seating = "Level One";
}
if (document.getElementsById('levelTwo').checked == true) {
seating = "Level Two";
}
if (document.getElementsById('balcony').checked == true) {
seating = "Balcony";
}
//Below is the checkbox printing
if (document.getElementById('checkbox1_0').checked == true) {
prefNight = 'Thursday';
}
if (document.getElementById('checkbox1_1').checked == true) {
prefNight = 'Friday';
}
if (document.getElementById('checkbox1_2').checked == true) {
prefNight = 'Saturday';
}
//Above is the checkbox printing
if (document.getElementById('news').checked == true) {
newsletter = "You wish to recieve our weekly E-mail";
}
if (document.getElementById('news').checked == false) {
newsletter = "You do not wish to recieve our weekly E-mail";
}
cost = parseInt(document.getElementById('selectmenu').value, 10) * numTickets; //This calculates the cost(selectMenu*numTickets)
var Orderemail = document.getElementById('txtOrderEmail').value; //This will grab the email value Inputed.
OrderInput += ("Your details are: <br />" + "Your E-mail address is: " + Orderemail + "<br />" + newsletter + "<br /> <br />" +
"You have the following tickets reserved: <br />" + numTickets + " on " + prefNight + " and your seating is :" + seating + "<br /> <br />" + "The total cost of your order will be: $" + cost);
document.getElementById('OrderInput').innerHTML = OrderInput; //This prints the users details to a html element.
document.getElementById('orderErrorMsg').innerHTML = ''; //Removes error messages when everything is correct.
}
return true;
}
Just a quick reminder of what I am trying to do:
I need to print a seating variable value to the OrderInput variable.
This Seating variable need to either be 'lower area', 'level one' 'balcony' or 'level two' Depending on what they click on(the options)
EDIT 2: seating = document.getElementById('selectmenu').options[document.getElementById('selectmenu').selectedIndex].text.split('(')[0]
Thanks to Teemu for catching that.
EDIT: After looking at your code, I guess you can just declare the variable as seating = document.getElementById('selectmenu').options[document.getElementById('selectmenu').selectedIndex].text.
Get the <select> element's .selectedIndex and use that to get its .options[selectedIndex].text, which is the text you want.
Here's a fiddle.
So #flowstoneknight has produced the correct answer. My new code is below. I now can get the value and multiply it by the number of tickets inputted aswell as Print the name of the seat in the orderInput
my html(It hasn't changed')
<div data-role="fieldcontain">
<label for="selectmenu" class="select">Preferred Seating:</label> <!-- Following drop down checkbox -->
<select name="selectmenu" id="selectmenu">
<option name="selectmenu" value="200" class="lowerLvl" id="lowerArea" >Lower Area($200)</option>
<option name="selectmenu" value="150" class="levelOne" selected="selected" id="levelOne">Level 1($150)</option>
<option name="selectmenu" value="100" class="levelTwo" id="levelTwo">Level 2($100)</option>
<option name="selectmenu" value="200" class="balcony" id="balcony">Balcony($200)</option>
</select>
</div>
<!--End of DropDownBoxes-->
<!--START OF CHECK BOXES-->
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Prefered night:</legend>
<input type="radio" name="checkbox1" id="checkbox1_0" class="custom" value="" checked="checked" /></option>
<label for="checkbox1_0">Thursday</label>
<br />
<input type="radio" name="checkbox1" id="checkbox1_1" class="custom" value="" />
<label for="checkbox1_1">Friday</label>
<br /><!--Break as on Example-->
<input type="radio" name="checkbox1" id="checkbox1_2" class="custom" value="" />
<label for="checkbox1_2">Saturday</label>
</fieldset><!-- Above are check boxes -->
</div>
<div data-role="fieldcontain">
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Subscribe to weekly newsletter: </legend>
<input type="checkbox" name="newletter" id="news" class="custom" value="" />
</fieldset>
</div>
<!--END OF CHECK BOXES-->
<!--Put a tick box here that asks for weekly mail-->
<button type="submit" value="Register" onClick="validateGalaOrder()"></button>
<p id="OrderInput"></p><!--USERS INPUT RETURNS TO THIS <P>-->
<p id="tktCost"></p>
<p id="orderErrorMsg"></p><!--INCORRECT INPUT MESSAGES RETURN TO THIS <P>-->
Here is the snippet of my Javascript, Please note I am only posting the select menu part which is in the else statement.
var seating = '';
seating = document.getElementById('selectmenu').options[document.getElementById('selectmenu').selectedIndex].text.split('(')[0]
cost = parseInt(document.getElementById('selectmenu').value,10) * numTickets;//This calculates the cost(selectMenu*numTickets)
var Orderemail = document.getElementById('txtOrderEmail').value;//This will grab the email value Inputed.
OrderInput +=("Thanks " + ValidateOrderName + " for your order!<br /> <br />" + "Your details are: <br />" + "Your E-mail address is: " + Orderemail + "<br />" + newsletter + "<br /> <br />" +
"You have the following tickets reserved: <br />" + numTickets +" on " + prefNight + " and your seating is :" + seating + "<br /> <br />" + "The total cost of your order will be: $" + cost);
document.getElementById('OrderInput').innerHTML = OrderInput;//This prints the users details to a html element.
document.getElementById('orderErrorMsg').innerHTML = '';//Removes error messages when everything is correct.
}
return true;
}