The question I have is how I would be able to change the value that is set in the text box that the autocomplete is linked to. The task I am attempting to do is to convert from YUI 2 to YUI 3. Please don't say that I shouldn't do that... because It isn't my choice. I am aware... The code below is what was used before. I already have the autocomplete functionality doing most of what it needs to do. It's just when it gets to the field.itemSelectEvent.subscribe(myHandler) part that I can no longer get anything else to work. The list comes up with the persons information but when selected it just puts [object Object] in the text box instead of their name that automatically forwards to another page. Thank you for your help!!!
var field = new YAHOO.widget.AutoComplete("webUserSearch",
"webUserSearchContainer", oDS);
field.highlightClassName = "autoCompleteHighlight";
field.useShadow = true;
field.queryMatchContains = true;
field.maxResultsDisplayed = 20;
field.resultTypeList = false;
field.formatResult = function(oResultData, sQuery) {
return "<div class=\"result\"><u style=\"cursor:pointer\">"
+ oResultData['Last Name'] + ", " + oResultData['First Name']
+ "</u> (" + oResultData['User Name'] + ")</div>";
};
var myHandler = function(sType, aArgs) {
var theField = aArgs[0];
var selectedElement = aArgs[1];
var repObject = aArgs[2];
theField.getInputEl().value = repObject['Last Name'] + ", "
+ repObject['First Name'];
var newTabURL = <URL Removed for Stack Overflow>;
window.location.href = newTabURL;
};
field.itemSelectEvent.subscribe(myHandler);
Listen for the select event, then in the handler for that you'll get a result object. The structure of that is described in the docs for the result event (a little up from the select event).
I usually take a value out of the raw property on the result object to stick into the field.
resultTextLocator was the ticket. All I had to do was to return the value I wanted to display in the box.
resultTextLocator : function (result) {
return result["Last Name"] +
', ' +
result["First Name"];
}
Related
My application is designed to create a table which is later edited by the user. After this I need my application to send the page content via email.
I used URLHelper's trigger email() but through this I am able to trigger the email with to, cc, subject, text body but my ui5 application is not able to insert the table into the email.
Can someone please suggest something? or is it even possible?
I won't mind using plain javascript either, Point is I need to do this without using the backend.
We do something similar on one of our apps. I added a button to the screen which when clicked invokes a 'mailto', and populates the email client with the to, subject and body. The body is created as part of the script. We basically read the table contents into an array, then loop through the entries using a forEach. Keep in mind using mailto or even the URLHelper does not allow you to use HTML formatted text in the 'body' of the email. So, if you're looking for something pretty, you may be out of luck.
onNotifyUserPress: function(oEvent) {
var oItem = oEvent.getSource();
var oBinding = oItem.getBindingContext();
// Set some vars for the email package
var sEmpEmail = oBinding.getProperty("Smtp");
var sEmpName = oBinding.getProperty("STEXT_2");
var sEmailSubject = "Your Subject " + sEmpName;
// Create DateFormat Object
var oDateFormat = DateFormat.getDateTimeInstance({pattern: "dd/MM/yyyy"});
// Retrieve Table Data
var oTable = this.getView().byId("yourTable");
var aTableData = oTable.getBinding("items").getContexts();
// Build the email body
var sBody = sEmpName + " - Some Body Text\n\n";
sBody += "Field 1 | " + "Field 2 | " + "Field 3 | " + "Field 4" + "\n";
// Loop through table data and build the output for the rest of the email body
aTableData.forEach(function(oModel) {
var oModelData = oModel.getObject();
var sEndDate = oDateFormat.format(oModelData.Vendd);
var sStatus = this._formatStatus(oModelData.ZQ_STAT);
sBody += (oModelData.Essential === "X" ? "Yes" : "No") + " | " + oModelData.Ttext + " | " + sEndDate + " | " + sStatus + "\n";
}.bind(this));
// Open email client window and prepopulate with info
window.open("mailto:" + sEmpEmail + "&subject=" + sEmailSubject + "&body=" + encodeURIComponent(sBody), "_self");
},
You'll obviously need to update the code to point to your table data. In this particular instance, we have an object page with a couple of sections. Each section contains a table which loads a list of entities that are associated with the user. As the data is already loaded and exists in the model, this may not work in the same fashion as what you're trying to do (if I understand correctly), as you need to send an email after the data is entered/modified?
Hopefully this can at least get you started!
Cheers!
My code is based on the example of google code:
https://developers.google.com/maps/articles/phpsqlinfo_v3
and was working fine.
I need to change a former 'gid' (Integer) field to 'id' (String) to get saved to the database and used to display a new labeled symbol on the map.
The strange thing is, that the url, that is build in the code to call the addrow.php file is OK. When I capture this string with alert(url), and I manually use this string, the new data is added to the database.
In my script, the call seems to fail (responseCode == 200 && data.length <=1), since no data is written to the database and the alert from the 'else-clause' is displayed as short pop-up.
Here's the code I use in my project (to save data from a form):
//save new marker to Postgis-database and add new markerwithlabel on the fly
function saveData(){
var gender = escape(document.getElementById("gender").value);
var hoehe = InZahl(document.getElementById("hoehe").value);
var breite = InZahl(document.getElementById("breite").value);
var id = escape(document.getElementById("id").value);
var vital = document.getElementById("vital").value;
var typ = document.getElementById("typ").value;
var ein_mehr = document.getElementById("ein_mehr").value;
var st_durchm = document.getElementById("st_durchm").value;
var frucht = document.getElementById("frucht").value;
var anmerk = document.getElementById("anmerk").value;
var latlng = marker.getPosition();
var url = "./mapdata/addrow.php?gender=" + gender +
"&hoehe=" + hoehe + "&lat=" + latlng.lat() + "&lng=" + latlng.lng() +
"&breite=" + breite + "&id=" + id + "&typ=" + typ + "&ein_mehr=" +ein_mehr + "&st_durchm=" + st_durchm +
"&frucht=" + frucht +
"&vital=" + vital + "&anmerk=" + anmerk;
downloadUrl(url, function (data, responseCode) {
if (responseCode == 200 && data.length <=1) {
infowindow.close();
marker.setDraggable(false);
marker.setIcon('./images/mm_purple.png');
marker.labelContent = id;
marker.setMap(map);
downloadUrl("./mapdata/getxml_get_last.php", function (data1) {
var xml = parseXml(data1);
var ms = xml.documentElement.getElementsByTagName("m");
var gid = ms[0].getAttribute("gid");
var html_n = "<div id='InfoWindow'><p style='font-weight:bold;'>" + id + "</p> \n\<p>Höhe:" + hoehe + " Breite: "+ breite +
"<br />\n\Typ: "+typ+" Stämme: "+ein_mehr+" St-Durchm: "+ st_durchm + "<br />\n\Vitalität: "+vital+" Fruchtbehang: "+frucht+
"<p/>\n\<p style='text-align:right;'><a href='sm_juniperus.php?operation=ssearch&ResetFilter=0&SearchField=gid&FilterType=%3D&FilterText="+ gid +
"' target='_blank'> Daten editieren </a></p></div>";
infowindow.setContent(html_n);
bindInfoWindow(marker, map, infowindow, html_n);
(function(i, marker, gid) {
var origIcon = marker.getIcon();
new LongPress(marker, 1000);
google.maps.event.addListener(marker, 'longpress', function(e) {
marker.setDraggable(true);
marker.setIcon(mmcross);
});
google.maps.event.addListener(marker, 'dragend', function(){
updatePosition(marker, gid);
marker.setIcon(origIcon);
});
})(i,marker,gid);
//add new marker to markerCluster-Array and to markerArray
markerCluster.addMarker(marker,false);
markerArray.push(marker);
i++;
}); // End add new marker
}
else {
alert("Your data couldn't be saved!");
}
}); // End downloadUrl
}; // END saveData()
As I said, my code worked fine, but after 3 evenings passed to solve this, I thought it would be time to ask for help.
If anybody has an idea, where the mistake lies, I would apreciate any hint.
Just to confirm, you're aware that you by doing
if (responseCode == 200 && data.length <=1) {
you are saying 'if the request is successful and the data it returns is only one character or below in length'? I am unsure if this is intended or not, because this way the code inside the if statement is only ran if the response is successful but contains only 1 or 0 characters.
Seem like I'm not the first to investigate this. But not despairing yet :-)
The target state I'd like to reach is:
A recursion through Packages, where some of the nested Sub-Packages are glorified Linked Documents, and some are Grids rendering Search Results.
I like that Model Documents provide Search Tag values -- but I can't seem to nest the grids where I want them to show up.
Approach 1: Nested Model Documents
If I could nest Model Document elements, with their Search/Search Term tags, I would be sorted. I could have
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Model Document <- renders the results of a canned Search.
But EA appears to be designed to ignore the Model Document element.
Approach 2: SQL backed Template Fragment
I like the Model Document as it has Search/Search Term + all the Inclusion/Exclusion configuration options. But if I had to give that part up I am thinking of emulating as much as I can via SQL or script.
First attempt - using SQL and a nested set of Packages such as:
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Package<> <- renders the results of a SQL Search.
If the template uses a TemplateSelector it can spot the Package with a wellknown stereotype, and invoke a Template that is backed by SQL.
The SQL uses the Package's Keywords as the source of the Element type to search for.
SELECT
o.ea_guid AS [CLASSGUID],
o.Object_Type AS [CLASSTYPE],
o.PDATA5 AS [KEYWORDS],
o.Object_Type AS [Type],
o.Stereotype AS [Stereotype],
*
FROM t_object as O
WHERE O.Object_Type IN
(SELECT PDATA5 FROM t_object AS S where S.Object_ID = #OBJECTID#)
It works...barely.It's a bit hacky.
Searching off of Element Type is not going to be sufficient for production documents.
Approach 3: Script backed Template Fragment
If I can get a script running I suspect that I could leverage functionality that is already in the system.
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Package<> <- renders the results of a canned Search.
If the template uses a TemplateSelector it can spot the Package with a wellknown stereotype, and invoke a Template that is backed by a script.
The script I'm trying is:
var x = Repository.GetElementsByQuery("POC.Req", "Device");
return x;
But the report remains blank of those elements I need for the table.
Q: Does the returned Collection need transformation before it can be used?
Approach 4
I've heard that there is an approach to Render Document sections as PDF, and link to them as Linked Documents... Sounds Convoluted. Sounds like a wrong/magic approach.
Approach 5
Any other suggestions?
Thanks for the help.
Addendum
Just got approach 3 to work by converting the script results to xml before handing it back
The template's script now looks like
-- first pass ...I'll work on passing the ObjectId in a bit in order to get fancier.
ExecuteSearch("Simple", "Device")
and it invokes a script saved somewhere else as
!INC Local Scripts.EAConstants-JScript
/*
* Script Name:
* Author:
* Purpose:
* Date:
*/
function main()
{
return ExecuteSearch("Simple", "Device");
}
function ExecuteSearch(searchName, searchParam){
var x = Repository.GetElementsByQuery(searchName, searchParam);
//return x;
var xmlDOC = CreateReport(x);
var s = xmlDOC.xml;
Session.Output(s);
return s;
}
function CreateReport(entityCollection){
var xmlDOC = CreateXmlDOC();
var xmlRoot = AppendXmlChild(xmlDOC,"EADATA");
var xmlDataSet = AppendXmlChild(xmlDOC,"Dataset_0",xmlRoot);
var xmlData = AppendXmlChild(xmlDOC,"Data",xmlDataSet);
for(var i = 0;i<entityCollection.Count();i++){
var entity = entityCollection.GetAt(i);
var xmlRow = AppendXmlChild(xmlDOC,"Row",xmlData);
//AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).Text = entity.Type;
AppendXmlChild(xmlDOC,"Guid",xmlRow).text = entity.ElementGUID;
AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).text = entity.Type;
AppendXmlChild(xmlDOC,"CLASSGUID",xmlRow).text = entity.ElementGUID;
AppendXmlChild(xmlDOC,"Type",xmlRow).text = entity.Type;
AppendXmlChild(xmlDOC,"Stereotype",xmlRow).text = entity.Stereotype;
AppendXmlChild(xmlDOC,"Name",xmlRow).text = entity.Name;
AppendXmlChild(xmlDOC,"Object",xmlRow).text = entity.Name;
AppendXmlChild(xmlDOC,"Id",xmlRow).text = entity.ElementID;
AppendXmlChild(xmlDOC,"Scope",xmlRow).text = entity.Scope;
AppendXmlChild(xmlDOC,"Phase",xmlRow).text = entity.Phase;
AppendXmlChild(xmlDOC,"Status",xmlRow).text = entity.Status;
var noteElement = AppendXmlChild(xmlDOC,"Notes",xmlRow);//.text = entity.Notes;
noteElement.appendChild(xmlDOC.createCDATASection(entity.Notes));
AppendXmlChild(xmlDOC,"Keywords",xmlRow).text = entity.PDATA5;
}
return xmlDOC;
}
function CreateXmlDOC()
{
var xmlDOM;
try
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.4.0" );
}
catch(e)
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.6.0" );
}
xmlDOM.createProcessingInstruction("xml","version=\"1.0\"");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
return xmlDOM;
}
function AppendXmlChild(xmlDOM, xmlElementName, xmlParent, isCDATA){
if (!xmlParent){xmlParent = xmlDOM;}
var child = xmlDOM.createElement(xmlElementName);
xmlParent.appendChild(child);
return child;
}
main();
The script I used in the end is as follows. It now correctly investigates the element's tags for clues as how to proceed.
Hope it helps others.
!INC Local Scripts.EAConstants-JScript
/*
* Script Name:
* Author:
* Purpose:
* Date:
*/
//Only used for development
function devTest()
{
//With Child elements: {2255D8C8-F1BB-4069-BDAF-8B303D108C62}
//With SearchName: {919252E0-BDEB-4f26-A39F-C0E74382952A}
//With PackageGUID: {8543ED3B-EC39-4bf0-92C2-FD49A00C376B}
Session.Output ("DEVTEST");
var package = Repository.GetPackageByGuid("{8543ED3B-EC39-4bf0-92C2-FD49A00C376B}");
Session.Output("Package Name:" + package.Name);
Session.Output("Package Guid:" + package.PackageGUID);
Session.Output("Package Id:" + package.PackageID);
Session.Output("Package ElementId:" + package.Element.ElementID);
//Session.Output("Package Element Id:" + package.Element.ElementID);
//Use the Element associate to the Package, not the Package ID itself.
var packageElementId = package.Element.ElementID; //NOT: package.PackageID;
var xmlDoc=ExecuteSearch(packageElementId);
try {
Session.Output(xmlDoc.xml);
}catch (e){
Session.Output(e.message);
}
}
//Extracts from a given Package it's SearchName/SearchValue tags
//in order to do a search that mimicks a ModelDocument's way of
//generating a report.
function ExecuteSearch(elementId){
//Validation
if (!elementId){
Session.Output("Exiting: No elementId received.");
return;
}
var packageElement = Repository.GetElementByID(elementId);
if (!packageElement){
Session.Output("Exiting: No package with given elementId: " + elementId);
return;
}
try {
var xmlDOC = ExecuteSearch2(packageElement);
var xml = xmlDOC.xml;
return xml;
}catch (e){
Session.Output("ERROR: " + e.message);
}
return null;
}
function ExecuteSearch2(packageElement){
//Session.Output(packageElement.ElementGUID + ": '" + packageElement.Name + "' invoking ExecuteSearch(" + packageElement.ElementID + ")");
//Session.Output("Attribute 'Test': " + GetElementTaggedValue(packageElement,'Test'));
//Precendence is to search
//* Direct children,
//* by Package, recursively,
//* Package, single
//* Package
//First dibs: does this package have any direct elements?
//Get back to the package that is related to the Element before you count Elements:
var package = Repository.GetPackageByGuid(packageElement.ElementGUID);
var elementCollection = package.Elements;
if (elementCollection.Count()){
Session.Output("Package [" + packageElement.ElementGUID + "] has child Elements:"+ elementCollection.Count());
return CreateReportDoc(elementCollection);
}
//If package had no children, look at Attributes for reference to other package.
//At present, can't find an easy way to determine package Id from the EA GUI, so
//using the Guid.
var searchPackageGuid = GetElementTaggedValue(packageElement,'SearchPackageGUID');
if (!searchPackageGuid){
searchPackageGuid = GetElementTaggedValue(packageElement,'SearchPackageGuid');
}
if (searchPackageGuid){
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchPackageGuid:"+ searchPackageGuid);
return ExecuteSearchByPackageGuid(searchPackageGuid);
}
// //If I ever find a way to get a packageId:
var searchPackageId = GetElementTaggedValue(packageElement,'SearchPackageId');
if (searchPackageId){
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchPackageId:"+ searchPackageId);
return ExecuteSearchByPackageId(searchPackageId);
}
// //If searching by SQL:
var searchSQL = GetElementTaggedValue(packageElement,'SearchSQL');
if (searchSQL){
Session.Output("Package [" + packageElement.ElementGUID + "] has SearchSQL:"+ searchSQL);
return ExecuteSearchBySQL(searchSQL);
}
//Not pointing to a package, so maybe pointing to a canned search:
var searchName = GetElementTaggedValue(packageElement,'SearchName');
if (!searchName){
//Session.Output("No SearchName");
return;
}
var searchValue = GetElementTaggedValue(packageElement,'SearchValue');
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchName/Value:"+ searchName + "/" + searchValue);
return ExecuteSearchBySearchName(searchName, searchValue);
}
//Mimicks functionality of a ModelDocument that searches by canned SearchName/SearchValue.
function ExecuteSearchBySearchName(searchName, searchValue){
var elementCollection = Repository.GetElementsByQuery(searchName, searchValue);
//return x;
return CreateReportDoc(elementCollection);
}
function ExecuteSearchByPackageGuid(packageGuid){
var package = Repository.GetPackageByGuid(packageGuid);
return ExecuteSearch2(package.Element);
}
function ExecuteSearchBySQL(searchSQL){
var elementCollection = Repository.GetElementSet(searchSQL, 2);
}
function HOLD_ExecuteSearchBySet(idList){
var elementCollection = Repository.GetElementsSet(idList);
//return x;
return CreateReportDoc(elementCollection);
}
//Iterate through the elements and convert to an Xml Document
//suitable for use by a Script backed Template:
function CreateReportDoc(elementCollection){
var xmlDOC = CreateXmlDOC();
var xmlData = CreateXmlReport(xmlDOC);
for(var i = 0;i<elementCollection.Count();i++){
//For each Element, create a new row:
var xmlRow = AppendXmlChild(xmlData,"Row");
//And embed the specific element:
var element = elementCollection.GetAt(i);
CreateReportRow(xmlRow, element);
}
return xmlDOC;
}
function CreateReportRow(xmlRow, element){
//And attach child property elements.
//For hairy ones, add them as a CDATA.
//AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).Text = element.Type;
AppendXmlChild(xmlRow,"Guid").text = element.ElementGUID;
AppendXmlChild(xmlRow,"CLASSTYPE").text = element.Type;
AppendXmlChild(xmlRow,"CLASSGUID").text = element.ElementGUID;
AppendXmlChild(xmlRow,"Type").text = element.Type;
AppendXmlChild(xmlRow,"Stereotype").text = element.Stereotype;
AppendXmlChild(xmlRow,"Name").text = element.Name;
AppendXmlChild(xmlRow,"Object").text = element.Name;
AppendXmlChild(xmlRow,"Id").text = element.ElementID;
AppendXmlChild(xmlRow,"Scope").text = element.Scope;
AppendXmlChild(xmlRow,"Phase").text = element.Phase;
AppendXmlChild(xmlRow,"Status").text = element.Status;
AppendXmlChild(xmlRow,"Keywords").text = element.PDATA5;
//Notes need wrapping as CDATA
var noteElement = AppendXmlChild(xmlRow,"Notes");//.text = entity.Notes;
noteElement.appendChild(xmlRow.ownerDocument.createCDATASection(element.Notes));
//Now get tags:
AppendXmlChild(xmlRow,"Tags.ID").text = GetElementTaggedValue(element,"ID");
AppendXmlChild(xmlRow,"Tags.Type").text = GetElementTaggedValue(element,"Type");
AppendXmlChild(xmlRow,"Tags.Category").text = GetElementTaggedValue(element,"Category");
AppendXmlChild(xmlRow,"Tags.Traceability").text = GetElementTaggedValue(element,"Traceability");
return xmlRow;
}
//helper function to create an empty xml document
function CreateXmlDOC()
{
var xmlDOM;
try
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.4.0" );
}
catch(e)
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.6.0" );
}
xmlDOM.createProcessingInstruction("xml","version=\"1.0\"");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
return xmlDOM;
}
//helper function to create the beginning of an xml document
//suitable to render the results of a search:
function CreateXmlReport(xmlDOC){
var xmlRoot = AppendXmlChild(xmlDOC,"EADATA");
var xmlDataSet = AppendXmlChild(xmlRoot,"Dataset_0");
var xmlData = AppendXmlChild(xmlDataSet,"Data");
return xmlData;
}
//helper function to attach a new child xml element to a parent xml element
function AppendXmlChild(xmlParent, xmlElementName, isCDATA){
var xmlDocument = xmlParent.ownerDocument;
if (!xmlDocument){xmlDocument = xmlParent}
var child = xmlDocument.createElement(xmlElementName);
xmlParent.appendChild(child);
return child;
}
//Gets an Element's tag. Eats exception if Tag does not exist.
function GetElementTaggedValue(element, tagName){
var tag;
try {
tag = element.TaggedValues.GetByName(tagName);
}
catch (e) {
}
if (!tag){return;}
var result = tag.Value;
return result;
}
function ConvertPackageIdToBranchId(packageId){
var package = Repository.GetPackageByID(objectId);
if (!package){return;}
var packages = [package];
packages.concat(ConvertPackageToBranch(package));
var result=[];
for(var i=0;i<packages.length;i++){
result.push(packages[i].PackageID);
}
return result;
}
function ConvertPackageToBranch(package){
var result = [];
for (var i=0;i<package.Packages.Count();i++){
var childPackage = package.Packages.GetAt(i);
result.push(childPackage);
result.concat(ConvertPackageToBranch(childPackage));
}
return result;
}
//devTest();
I feel like this should be so easy and obvious, but I cannot figure it out...
I am working with 2 forms and 2 spreadsheets. Form 1 submits to Sheet 1. On Sheet 1, for each record, there is a link that takes the user to Form 2, which is half pre-populated with data from Sheet 1. When the user submits Form 2, it populates Sheet 2.
I have a couple of scripts that are supposed to be triggered when Form 1 is submitted. I am using the "From Spreadsheet" "OnFormSubmit" trigger. The scripts, however, are also triggering when Form 2 is submitted.
How can I make it so the scripts only execute when Form 1 is submitted? Also, is there a way to ensure that scripts trigger in a specific order?
If it helps, the scripts are below. They all work properly as is, except for the triggering issue. I know that I can merge the 2nd and 3rd script, and I will, but I'd like to fix this triggering issue first, as I'm getting double the emails every time I test.
1st script:
function onFormSubmit(e) {
//Uses time in milleseconds to create unique ID #
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("ComplaintLog");
var d = new Date();
var n = d.getTime();
var lastRow = sheet.getLastRow();
var cell = sheet.getRange("BA" + lastRow);
cell.setValue(n);
var cell = sheet.getRange("BB" + lastRow);
cell.setFormula("=right(BA"+lastRow+",6)");
sheet.getRange("BB"+lastRow).copyTo(sheet.getRange("BC"+lastRow), +
{contentsOnly:true});
}
2nd script:
function formSubmitReply(e) {
//Sends email to certain users when a new complaint has been entered
var emailAddresses = 'person#organzation.com';
MailApp.sendEmail(emailAddresses,
"person#organzation.com",
"New Guest Complaint",
"A new guest complaint has been entered into the database."
+ "\n\n To vew the database, click here: http://goo.gl/DI33EC");
}
3rd script:
function createResolutionForm() {
var ss = SpreadsheetApp.getActive()
var sheet = ss.getSheetByName("ComplaintLog")
var lastRow = sheet.getLastRow();
var data = ss.getSheetByName("ComplaintLog") +
.getRange("A"+lastRow+":Z"+lastRow).getValues();
var form = FormApp.openById('The form's ID goes here. that part works.');
var items = form.getItems();
for (var i = 0; i < data.length; i++) {
var formResponse = form.createResponse();
//ID
var formItem = items[1].asTextItem();
var response = formItem.createResponse(data[i][0]);
formResponse.withItemResponse(response);
//Guest Name
var formItem = items[2].asTextItem();
var response = formItem.createResponse(data[i][3]);
formResponse.withItemResponse(response);
//email
var formItem = items[3].asTextItem();
var response = formItem.createResponse(data[i][4]);
formResponse.withItemResponse(response);
// The pre-populated form is being created here. I didn't include every
// form item for brevity's sake.
}
//Create Link
var formUrl = formResponse.toPrefilledUrl();
//Enable Clickable ID
var idNum = sheet.getRange("BC"+lastRow).getValues();
sheet.getRange("A"+lastRow).setFormula +
('=HYPERLINK("' + formUrl + '","' + idNum + '")');
var sheetUrl = "The URL to the spreadsheet goes here - that part works.";
//Send Email to assigned managers
var j,tempname=[],name, subject, managername, message;
managername = sheet.getRange("P"+lastRow).getValue();
tempname=managername.split(" ");
Logger.log(managername)
if (tempname.length==2) {
name=tempname[0].slice(0,1) + tempname[1] + '#organization.com';
subject = 'Action Required';
var message = "<html><body>"
+ "<p> You have been assigned to follow-up on a complaint,"
+ "or your contact information has been given to a customer in"
+ "regards to a complaint."
+ "<p><p>The complaint ID number is " + idNum +"."
+ "<p>To go directly to this complaint,"
+ "<b>click here</b>."
+ "<p>To vew the database so that you can take action,"
+click here."
+ "</body></html>";
MailApp.sendEmail(name, subject,"",{htmlBody : message});
}
}
Setting up the triggers from within the script might be what you're looking for. You can create triggers that respond to form submission events on a per-form basis like so:
function setup () {
ScriptApp.newTrigger('onForm1ResponseHandler').forForm(form1).onFormSubmit().create();
ScriptApp.newTrigger('onForm2ResponseHandler').forForm(form2).onFormSubmit().create();
}
where form1 and form2 are Form objects and 'onForm1ResponseHandler' is the name of the handler function.
With a handler function set up like this:
function onForm1ResponseHandler (e) {
...
}
e will be an object with properties documented here (for the Form Submit event).
I'm trying to create a script for a student attendance spreadsheet that will look in Column E for the string "X". For each instance of "X", the string from column A (the student name) will be added to the body of an email. I'm pretty new to JavaScript, although I have been studying the basics. I've done a lot of research and found some scripts I was able to modify to send an individual email for each instance of X in E. However, I have not been able to figure out how to combine that information into a single email.
Here's what I have so far:
function Email_ReminderNS() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("July_August"),
EMAIL_SENT = "EMAIL_SENT",
statusArray = sheet.getDataRange().getValues();
var class = statusArray[0][8],
status = "X",
email = "XXXX"
for (i=7;i < statusArray.length;i++){
var emailSent = statusArray[i][84];
if (status == statusArray[i][4] & emailSent != EMAIL_SENT) {
var student = statusArray[i][0];
var body = "This is a No-Show Report for " +student+ " from " + class;
var subject = "No-Show Report for " + student+ " from " + class;
MailApp.sendEmail(email,subject,body,{NoReply : true});
sheet.getRange(i+1, 85).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
I realize I'll probably need to move the sendEmail function to be outside the IF statement. I tried to create an array with the names and join those into a string and add it to the body of the email, but I've had no luck. It just ended up sending the last name instead of all of them.
If anyone has any suggestions for me I would be deeply grateful.
First set up variables to keep track of which student did not show up:
var students = [];
var student_rows = [];
Then, add student to these arrays when X is found:
if (status == statusArray[i][4] & emailSent != EMAIL_SENT) {
var student = statusArray[i][0];
students.push(student);
student_rows.push(i+1);
}
Then send the email with all student names combined (outside of the for loop like you said)
var body = "This is a No-Show Report for " + students.join(', ') + " from " + class;
var subject = "No-Show Report for " + students.join(', ') + " from " + class;
MailApp.sendEmail(email,subject,body,{NoReply : true});
Finally update the spreadsheet indicating which names were in that email:
for (var i=0; i<student_rows.length; i++) {
sheet.getRange(student_rows[i], 85).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
Here's the complete script:
function Email_ReminderNS() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("July_August"),
EMAIL_SENT = "EMAIL_SENT",
statusArray = sheet.getDataRange().getValues();
var class = statusArray[0][8],
status = "X",
email = "francis#bposolutions.com";
var students = [];
var student_rows = [];
for (i=7;i < statusArray.length;i++){
var emailSent = statusArray[i][84];
if (status == statusArray[i][4] & emailSent != EMAIL_SENT) {
var student = statusArray[i][0];
students.push(student);
student_rows.push(i+1);
}
}
var body = "This is a No-Show Report for " + students.join(', ') + " from " + class;
var subject = "No-Show Report for " + students.join(', ') + " from " + class;
MailApp.sendEmail(email,subject,body,{NoReply : true});
for (var i=0; i<student_rows.length; i++) {
sheet.getRange(student_rows[i], 85).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
There are probably many ways to implement a new version of your code, the other answer probably works but I think it can be improved (a bit).
First of all, you can get rid of the flush method that does nothing else than slowing down the function (it was originally used in the Google example to check the sent status row by row, it is useless when we send only one mail with all the data in it)
Secondly, it might be a good idea to use html format to get a better looking result.
And lastly, it is good practice to write back to the sheet using one setValues instead of multiple setValue() in a loop.
Here is a possible replacement code, you'll have to "tune" it to your needs to eventually improve the message format but the main structure is there and working.
function Email_ReminderNS() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("July_August"),
statusArray = sheet.getDataRange().getValues();
var email = Session.getActiveUser().getEmail(); //replace with the email you want, this value will send mails to you I used it for test.
var class = statusArray[0][8],
status = "X",
students = [];
for (var i=7;i < statusArray.length; i++){
var emailSent = statusArray[i][84];
if (status == statusArray[i][4] & emailSent != "EMAIL_SENT") {
students.push(statusArray[i][0]);
statusArray[i][84]="EMAIL_SENT";
}
}
var subject = "No-Show Report for " + students.length + " from " + class;
var textBody = "This is a No-Show Report for " +students.length+ " from " + class+"\n";
var HTMLBody = "<b>This is a No-Show Report for " +students.length+ " from " + class+"</b><br><br>"
+'<table style="background-color:lightblue;border-collapse:collapse;" border = 1 cellpadding = 5><th>Sent Mails</th><tr>';
for(var n in students){
HTMLBody += '<tr><td>'+n+'</td><td>'+statusArray[n][0]+'</td></tr>';
textBody += '\n'+n+' - '+statusArray[n][0];
}
HTMLBody+='</table><BR> kind regards.' ;
textBody+='\n\nKind regards';
Logger.log(HTMLBody);
Logger.log(textBody);
MailApp.sendEmail(email,subject,textBody,{'NoReply' : true, 'htmlBody' : HTMLBody});
sheet.getRange(1,1,statusArray.length,statusArray[0].length).setValues(statusArray);
}