更新
在指定列 O 中的条目将由人类创建之后
并将触发onEdit() 触发器,这是一个简单而优雅的
使用event objects的解决方案:
onEdit(e){
if( e.range.getSheet().getName()=='Sheet1' &&
e.range.getColumn()==15&&e.value=="Complete"&&e.oldValue!="Complete"){
sendMail(e.range.getRow(),e.value);
}
}
您可以将function checkComplete() 及其 onChange 触发器替换为
这个onEdit 函数。
查看您的电子表格后,我注意到以下问题:
正如我在评论中提到的,onEdit 将由电子表格中任何工作表的更改触发,但您希望代码仅针对工作表“仪表板”中的更改运行。此外,您不希望将Dashboard 中的列 O 与其他工作表中的列 O 进行比较 - 所有条目都将不同,并会触发对 sendMail 的调用。在继续执行其余代码之前,您应该在 "Dashboard 的开头实现一个条件语句来验证您是否在正确的工作表中。
你的函数sendMail包含
var rank = SpreadsheetApp.getActiveSheet().getRange(row,1).getValue();
var totalranked = SpreadsheetApp.getActiveSheet().getRange(4,1).getValue();
var address = SpreadsheetApp.getActiveSheet().getRange(row,2).getValue();
var score = SpreadsheetApp.getActiveSheet().getRange(row,6).getValue();
var outlook = SpreadsheetApp.getActiveSheet().getRange(row,14).getValue();
var ildemand = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('1-Dmnd').getRange(row+1,9).getValue();
var aldemand = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('1-Dmnd').getRange(row+1,14).getValue();
var mcdemand = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('1-Dmnd').getRange(row+1,19).getValue();
var increase = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('2-Comp').getRange(row,11).getValue();
var occupancy = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('2-Comp').getRange(row,13).getValue();
var medHHI = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('4-Demo').getRange(row+2,17).getValue();
var medHV = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('4-Demo').getRange(row+2,19).getValue();
var walkscore = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('3-Muni').getRange(row,19).getValue();
var dmnd = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('1-Dmnd').getRange(row+1,5).getValue()
var comp = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('2-Comp').getRange(row,5).getValue();
var muni = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('3-Muni').getRange(row,5).getValue();
var grade = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('3-Muni').getRange(row,17).getValue();
var demo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('4-Demo').getRange(row+2,5).getValue();
这是对 SpreadsheetApp 的 18 次调用,每次调用 sendMail。如果您将两个不同工作表的 O 列相互比较(参见 1.),则乘以 sendMail 将被调用的时间量!请注意,对外部服务的任何请求都非常耗时且效率低下,应避免,请参阅Best Practices。在sendMail 之外,您应该只检索一次所有这些变量。鉴于此后sendMail 的代码将很短,您可以直接在for 循环中实现它。
如果在工作表的开头而不是结尾附加了一行 - 这会将新值与旧值相比较,因此,每一行都会触发 sendMail 的调用。您可以避免使用 indexOf 检查新内容是否包含在旧内容的数组中。
从 Apps 脚本编辑器 UI 转到 Edit->Current project's triggers 并检查您是否不小心将多个触发器附加到文件,这些触发器都同时运行。
考虑到第 1.、2. 和 3. 点,以下是对您的代码的改进建议:
var admin_email=XXXXX; //<- list email addresses here
function checkComplete() {
var ss=SpreadsheetApp.getActive();
var sh = ss.getActiveSheet();
if(sh.getName()=="Dashboard"){
var values = sh.getRange('O14:O').getValues().join('-');
if(PropertiesService.getScriptProperties().getKeys().length==0){ // first time you run the script
PropertiesService.getScriptProperties().setProperty('oldValues', values);
return;
}
var oldValues = PropertiesService.getScriptProperties().getProperty('oldValues').split('-');
var valuesArray = values.split('-');
while (valuesArray.length>oldValues.length){
oldValues.push('x'); // if you append some rows since last exec
}
Logger.log('oldValues = '+oldValues)
Logger.log('current values = '+valuesArray)
for(var n=0;n<valuesArray.length;n++){
if(oldValues.indexOf(valuesArray[n])==-1){ // check for any difference
Logger.log('value changed on row '+n+1+' value = '+valuesArray[n]+' , mail sent');
sendMail(n+1,valuesArray[n]);
}
}
PropertiesService.getScriptProperties().setProperty('oldValues', values);
}
}
function sendMail(row,val){
Logger.log('value changed on row '+row+' value = '+val+' , mail sent');
var rank = sh.getRange(row,1).getValue();
var totalranked = sh.getRange(4,1).getValue();
var address = sh.getRange(row,2).getValue();
var score = sh.getRange(row,6).getValue();
var outlook = sh.getRange(row,14).getValue();
var ildemand = ss.getSheetByName('1-Dmnd').getRange(row+1,9).getValue();
var aldemand = ss.getSheetByName('1-Dmnd').getRange(row+1,14).getValue();
var mcdemand = ss.getSheetByName('1-Dmnd').getRange(row+1,19).getValue();
var increase = ss.getSheetByName('2-Comp').getRange(row,11).getValue();
var occupancy = ss.getSheetByName('2-Comp').getRange(row,13).getValue();
var medHHI = ss.getSheetByName('4-Demo').getRange(row+2,17).getValue();
var medHV = ss.getSheetByName('4-Demo').getRange(row+2,19).getValue();
var walkscore = ss.getSheetByName('3-Muni').getRange(row,19).getValue();
var dmnd = ss.getSheetByName('1-Dmnd').getRange(row+1,5).getValue()
var comp = ss.getSheetByName('2-Comp').getRange(row,5).getValue();
var muni = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('3-Muni').getRange(row,5).getValue();
var grade = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('3-Muni').getRange(row,17).getValue();
var demo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('4-Demo').getRange(row+2,5).getValue();
// MailApp.sendEmail(admin_email,'EARLY results for '+address+' are ready!','EARLY says the Site is '+outlook+' and ranks # '+rank+' out of '+totalranked+' with an overall Score of '+score+'. The projected Net Demand is '+dmnd+' with: IL '+ildemand+' units, AL '+aldemand+' units and MC '+mcdemand+' units. The competitive environment is '+comp+' with an occupancy rate of '+occupancy*100+'% for nearby properties, and an expected supply increase of '+increase*100+'%. The location is '+walkscore+', and its public schools have a grade of '+grade+' making it '+muni+'. The demographic trends are '+demo+' with Median HHI of $'+medHHI+' and a median Home Value of $'+medHV+'. For more information, please visit https://docs.google.com/spreadsheets/d/1ydcXQilx6hxhI6HPpWTPT7Bq9a-gXPa7h8UC6KL9W8c/edit?usp=sharing.');
// add senior growth rate(s) to the Demographic summary sentence - Sept 3 2019
}