【问题标题】:Google Sheets Apps Script On Edit Remove Editors From Protected Range Very Slow / Not Completing编辑时的 Google Sheets Apps 脚本从受保护范围中删除编辑器非常慢/未完成
【发布时间】:2018-03-06 04:18:24
【问题描述】:

我对 Google Apps 脚本比较陌生,并且在使用下面的代码时遇到了困难。基本上,它绑定到充当工作流的工作表。我使用已安装的 onEdit 触发器,它会循环查看哪些单元格已更改,然后根据已更改的单元格添加时间戳、发送电子邮件或保护范围。

我遇到了时间戳并不总是持久的问题,电子邮件并不总是发送,而且保护措施永远存在。

有没有更有效的方法来做到这一点?

function onEditFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();

  // CHECKS FOR CHANGE IN "UPDATES" SHEET ONLY
  if (sheet.getSheetName() == "Updates") {
    var activeRange = sheet.getActiveCell();
    var activeRow = activeRange.getRow();
    var activeColumn = activeRange.getColumn();

    var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Updates');
    var sss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LookUps');

    var email = Session.getActiveUser().getEmail();
    var timestamp = new Date();

    var itemAttributes = sheet.getRange(activeRow, 1,activeRow,19).getValues();

  // CHECKS FOR CHANGE IN ITEM COLUMN (A)
    // if column A clear out the other cells
    if (activeColumn == 1) { 
      var r = sheet.getActiveRange();

      // CHECKS IF NUMBER OF ROWS INDICATES A PASTED RANGE
      // if pasted range is more than one row in size, then loop through and do validation on all impacted rows
      if (r.getNumRows() > 1) {  
        SpreadsheetApp.getActiveSpreadsheet().toast('Updating.....please wait.', 'Status', -1);
        var l = r.getNumRows()
        sheet.getRange(activeRow, 2, l, 13).clearContent();
        for (var x = 0; x < l; x++) {
          var ac = activeRow + x
          if(ss.getRange(ac, 1).getvalue != '') {
            sheet.getRange(ac, 12).setValue(email);
          }
          ss.getRange(ac, 1).copyTo(sss.getRange('G1'), {contentsOnly:true})    
          var dynamicList = sss.getRange('G2:G15');   // set to your sheet and range
          var arrayValues = dynamicList.getValues();
          var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
          ss.getRange(ac, 2).setDataValidation(rangeRule); // set range to your range

          //SpreadsheetApp.flush();
          var NewItemCheck = sss.getRange('G2').getValues()
          if (NewItemCheck == "" && ss.getRange(ac, 1).getvalue != '') {
            sheet.getRange(ac, 10).setValue("NEW ITEM") 
          }
        }  // END FOR LOOP THROUGH ROWS OF RANGE

        SpreadsheetApp.getActiveSpreadsheet().toast('DONE', 'Status', 2);
      }  // END IF RANGE IS GREATER THAN 1 ROW
      else
      {
        sheet.getRange(activeRow, 2, 1, 13).clearContent();
        if(itemAttributes[0][0] != '') {
          sheet.getRange(activeRow, 12).setValue(email);
        }
        sss.getRange('G1').setValue(itemAttributes[0][0]);
        var dynamicList = sss.getRange('G2:G15');
        var arrayValues = dynamicList.getValues();
        var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
        ss.getRange(activeRow, 2).setDataValidation(rangeRule);
        //SpreadsheetApp.flush();
        var NewItemCheck = sss.getRange('G2').getValues()
        if (NewItemCheck == "" && itemAttributes[0][0] != '') {
          sheet.getRange(activeRow, 10).setValue("NEW ITEM") 
        }
      }
    }

  // CHANGE IN Vendor Name / ID - LOC COLUMN (B)
    if (activeColumn == 2) {
      // if column B in Sheet UPDATES is changed, update adjacent drops downs
      sheet.getRange(activeRow, 5).clearContent();
      sss.getRange('H1').setValue(itemAttributes[0][1])

      var dynamicList = sss.getRange('H2:H15');

      var arrayValues = dynamicList.getValues();
      var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
      ss.getRange(activeRow, 5).setDataValidation(rangeRule);

      var a = itemAttributes[0][1].slice(-9);
      var b = a.split(" ");
      var c = itemAttributes[0][1].slice(-2);

      var vendLocCombo = [[b,c]];
      var vendLocComboRange = ss.getRange(activeRow, 3, 1, 2);
      vendLocComboRange.setValues(vendLocCombo);
    } 

    // SUBMITTED
    if (activeColumn == 11 && itemAttributes[0][10] ){
      // if column K in Sheet UPDATES is changed to TRUE (checked), email
      // cost analysts in var CostEmail, and protect submitted info
      sheet.getRange(activeRow, 13).setValue(timestamp);
      SpreadsheetApp.flush();

      var Prange = sheet.getRange('A'+activeRow+':M'+activeRow);
      var protection = Prange.protect().setDescription('SubmitLock A'+activeRow+':M'+activeRow);
      protection.removeEditors(protection.getEditors());
      protection.addEditors(['emailhere.com','emailhere.com']);

      if (protection.canDomainEdit()) {
        protection.setDomainEdit(false);
      }
    }

    // COMPLETED
    if (activeColumn == 15 && itemAttributes[0][14]) {
      // if column O in Sheet is changed to TRUE (checked) then user email and timestamp columns Q and R 
      sheet.getRange(activeRow, 17).setValue(email);
      SpreadsheetApp.flush();
      sheet.getRange(activeRow, 18).setValue(timestamp);
      SpreadsheetApp.flush();
      var Prange = sheet.getRange('N'+activeRow+':S'+activeRow);
      var protection = Prange.protect().setDescription('CompleteLock N'+activeRow+':S'+activeRow);
      protection.removeEditors(protection.getEditors());
      protection.addEditors(['emailhere.com','emailhere.com']);

      if (protection.canDomainEdit()) {
        protection.setDomainEdit(false);
      }
    }

    // DENIED
    if (activeColumn == 16 && itemAttributes[0][15]) {
      // if column P in Sheet is checked (true) send email to original submitter in column M
      sheet.getRange(activeRow, 17).setValue(email);
      sheet.getRange(activeRow, 18).setValue(timestamp);

      var Prange = sheet.getRange('O'+activeRow+':T'+activeRow);
      var protection = Prange.protect().setDescription('CompleteLock O'+activeRow+':T'+activeRow);
      protection.removeEditors(protection.getEditors());
      protection.addEditors(['emailhere.com','emailhere.com']);

      if (protection.canDomainEdit()) {
        protection.setDomainEdit(false);
      }

      var DeniedEmailAddress = itemAttributes[0][11];
      var message = "  Comments :     "+itemAttributes[0][13];
      var subject = "[Denied - Contracted Cost Request] "+itemAttributes[0][0];

      MailApp.sendEmail(DeniedEmailAddress, subject, message,{
          name: 'Contracted Cost Update',
          attachments: []
      });

      sheet.getRange(activeRow, 19).setValue("X");
    }
  }
}

编辑:

function onEditFunction(e) {

  if (e.source.getActiveSheet().getSheetName() == "Updates") {
    // CHECKS FOR CHANGE IN "UPDATES" SHEET ONLY

    var sheet = e.source.getActiveSheet();
    var protectionDescription;
    var protectedRange;
    var i;
    var protection;

    var removeEditorsArray = 
["group1@email.com","group2@email"];

    var activeColumn = e.range.getColumn();

    switch(activeColumn){
        case 1: //Item
            changeItem(e, sheet, activeColumn);
            break;
        case 2: //Vendor Name/ID - Loc 
            changeVendor(e, sheet, activeColumn);
            break;
        case 11: //SUBMIT check box
            changeSubmit(e, sheet, activeColumn, protectionDescription, protectedRange, removeEditorsArray);
            break;
        case 15: //COMPLETE check box
            changeComplete(e, sheet, activeColumn);
            break;
        case 16: //DENIED check box
            changeDenied(e, sheet, activeColumn);
            break;
    }
  }
}


function changeSubmit(e, sheet, activeColumn, protectionDescription, protectedRange, removeEditorsArray){
    // if column K in Sheet UPDATES is changed to TRUE (checked), enter a  timestamp and protect submitted info 

    var activeRow = e.range.getRow();
    var timestamp = new Date();
    var removeLen = removeEditorsArray.length

    sheet.getRange(activeRow, 13).setValue(timestamp);  

    protectedRange = 'A'+activeRow+':M'+activeRow;
    protectionDescription = 'SubmitLock A'+activeRow+':M'+activeRow;

    protectRanges(sheet, protectionDescription, protectedRange, removeEditorsArray)
}

function protectRanges(sheet, protectionDescription, protectedRange, removeEditorsArray) {

    var i=0;
    var Len = removeEditorsArray.length;

    protectedRange = sheet.getRange(protectedRange);
    protectionDescription = protectedRange.protect().setDescription(protectionDescription);

    for (i; i < Len; i++) {
        protectionDescription.removeEditor(removeEditorsArray[i]);
    }
}

【问题讨论】:

  • 你已经发布了很多代码,而且都是一个函数——我建议至少将这个函数分成 3 个函数,每个函数处理你想要执行的单个任务。接收onEdit 触发器的函数将使用逻辑调用所需的函数,并传递任何相关参数。我还建议访问可用于onEdit 触发函数的event object
  • 我必须在这里第二次 tehhowch。您的活动电子表格、活动单元格,甚至更改前后单元格中的值都可以通过事件对象访问(例如,您可以编写onEdit(e)e 将包含您需要的内容。请拆分代码,因为它需要一次全部完成。关于执行操作的逻辑的快速提示,使用 switch 而不是单独的 if 语句
  • @tehhowch - 感谢您的建议!我已经编辑了代码——我按功能分解了它,并利用了事件对象。现在,我可以更清楚地查看执行脚本,并且该脚本运行所需的 80-90 秒中有 98% 位于“Protection.removeEditor”上。我为此使用了一个数组,但我也尝试过仅使用一个文本字段的“Protection.removeEditorS”,它仍然需要大约相同的大量时间。我基本上是在尝试从编辑器列表中删除工作表中给定受保护范围的 2 个组名(对工作表具有编辑访问权限)。
  • @Vytautas - 谢谢!我编辑了,现在使用 switch 功能。更容易分析正在发生的事情以及进行编辑时。也使用(e)。从范围中移除保护仍然需要很长时间。有什么想法吗?
  • @Three-D,绝对是一个进步,干得好。我会更进一步(您错误地引用了e.source.getActiveSheet() 而不是e.range.getSheet() - 用户可以在此函数运行时更改选项卡),parameter passing 未来可能会出现问题。我只会将保护变量移到需要它们的地方(在changeSubmit 内,并作为protectRanges 的参数)。我还建议只使用批处理方法removeEditors(String[])。保护区有多大?

标签: google-apps-script google-sheets


【解决方案1】:

感谢@tehhowch 和@Vytautas 的帮助,我能够提出一个非常有效的代码,但确实必须将保护更改为仅警告,这对于工作表来说很好。

请看下面:

function onEditFunction(e) {

  if (e.range.getSheet().getSheetName() == "Updates") {
    // CHECKS FOR CHANGE IN "UPDATES" SHEET ONLY

    var protectedRange;
    var protectionDescription;

    var sheet = e.range.getSheet();
    var activeColumn = e.range.getColumn();

    switch(activeColumn){
        case 1: //Item
            changeItem(e, sheet, activeColumn);
            break;
        case 2: //Vendor Name/ID - Loc 
            changeVendor(e, sheet, activeColumn);
            break;
        case 11: //SUBMIT check box
            changeSubmit(e, sheet);
            break;
        case 15: //COMPLETE check box
            changeComplete(e, sheet, activeColumn);
            break;
        case 16: //DENIED check box
            changeDenied(e, sheet, activeColumn);
            break;
    }
  }
}

function changeSubmit(e, sheet){
    // if column K in Sheet UPDATES is changed to TRUE (checked), enter a timestamp and protect submitted info 

    var activeRow = e.range.getRow();
    var timestamp = new Date();
    var l = e.range.getNumRows();

    if (l > 1){ // if pasted range is more than one row in size, then loop through and do validation on all impacted rows
      SpreadsheetApp.getActiveSpreadsheet().toast('Updating.....please wait.', 'Status',-1);
      }

    for (var x = 0; x < l; x++) {
          sheet.getRange(activeRow + x, 13).setValue(timestamp);
//          SpreadsheetApp.flush();

          protectedRange = 'A'+(activeRow + x) +':M'+(activeRow + x);
          protectionDescription = 'SubmitLock A'+(activeRow + x)+':M'+(activeRow + x);
          protectRanges(sheet, protectionDescription, protectedRange);
        }
    if (l > 1){ // if pasted range is more than one row in size, then loop through and do validation on all impacted rows
      SpreadsheetApp.getActiveSpreadsheet().toast('DONE', 'Status',2);
      }
}

function changeComplete(e, sheet, activeColumn){
  // if column O in Sheet is changed to TRUE (checked) then user email and timestamp columns Q and R 

    var activeRow = e.range.getRow();

    var newData = [];

    var email = Session.getActiveUser().getEmail();
    var timestamp = new Date();

    newData = [[email],[timestamp]];


    sheet.getRange(activeRow, 17, activeRow, 18).setValues(newData);


    protectedRange = 'N'+activeRow+':S'+activeRow;
    protectionDescription = 'CompleteLock N'+activeRow+':S'+activeRow;
    protectRanges(sheet, protectionDescription, protectedRange);
}

function changeItem(e, sheet, activeColumn){

    var activeRow = e.range.getRow();

    var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Updates');
    var sss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LookUps');

    var email = Session.getActiveUser().getEmail();

    var l = e.range.getNumRows();
    var itemAttributes = sheet.getRange(activeRow, 1,(activeRow + l - 1),19).getValues();

    if (l > 1){ // if pasted range is more than one row in size, then loop through and do validation on all impacted rows
      SpreadsheetApp.getActiveSpreadsheet().toast('Updating.....please wait.', 'Status',-1);
      }

        for (var x = 0; x < l; x++) {
          if(itemAttributes[x][0] != ''){
            sheet.getRange(activeRow + x, 2,l, 13).clearContent(); // clears out row if new entry for item id
            sheet.getRange(activeRow + x, 12).setValue(email);  // stamps user in created by column
            }

        sss.getRange('G1').setValue(itemAttributes[x][0]);
        var dynamicList = sss.getRange('G2:G15');
        var arrayValues = dynamicList.getValues();
        var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
        ss.getRange(activeRow + x,2).setDataValidation(rangeRule);

          var NewItemCheck = sss.getRange('G2').getValues()

          if (NewItemCheck == "" && itemAttributes[x][0] != '') {
            sheet.getRange(activeRow + x, 10).setValue("NEW ITEM") 
            }
          }

    if (l > 1){ // if pasted range is more than one row in size, then loop through and do validation on all impacted rows
      SpreadsheetApp.getActiveSpreadsheet().toast('DONE', 'Status',2);
      }
}

function changeVendor(e, sheet, activeColumn){
     // if column B in Sheet UPDATES is changed, update adjacent drops downs

    var activeRow = e.range.getRow();

    var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Updates');
    var sss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LookUps');

    var itemAttributes = sheet.getRange(activeRow, 1,activeRow,19).getValues();

    sheet.getRange(activeRow, 5).clearContent();

    sss.getRange('H1').setValue(itemAttributes[0][1])

    var dynamicList = sss.getRange('H2:H15');

    var arrayValues = dynamicList.getValues();
    var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
    ss.getRange(activeRow,5).setDataValidation(rangeRule);

    var a = itemAttributes[0][1].slice(-9);
    var b = a.split(" ");
    var c = itemAttributes[0][1].slice(-2);

    var vendLocCombo = [[b,c]];
    var vendLocComboRange = ss.getRange(activeRow, 3, 1, 2);
    vendLocComboRange.setValues(vendLocCombo);
} 

function changeDenied(e, sheet, activeColumn){
  // if column P in Sheet is checked (true) send email to original submitter in column M

    var activeRow = e.range.getRow();

    var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Updates');
    var sss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LookUps');

    var email = Session.getActiveUser().getEmail();
    var timestamp = new Date();

    var itemAttributes = sheet.getRange(activeRow, 1,activeRow,19).getValues();

      sheet.getRange(activeRow, 17).setValue(email);
      sheet.getRange(activeRow, 18).setValue(timestamp);

    protectedRange = 'N'+activeRow+':S'+activeRow;
    protectionDescription = 'CompleteLock N'+activeRow+':S'+activeRow;
    protectRanges(sheet, protectionDescription, protectedRange);

    var DeniedEmailAddress = itemAttributes[0][11];
    var message = "  Comments :     "+itemAttributes[0][13];
    var subject = "[Denied - Contracted Cost Request] "+itemAttributes[0][0];

    MailApp.sendEmail(DeniedEmailAddress, subject, message,{
        name: 'Contracted Cost Update',
        attachments: []
        });

    sheet.getRange(activeRow, 19).setValue("X");
}

function protectRanges(sheet, protectionDescription, protectedRange) {

    protectedRange = sheet.getRange(protectedRange);
    protectionDescription = protectedRange.protect().setDescription(protectionDescription);
    protectionDescription.setWarningOnly(true);
    SpreadsheetApp.flush();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多