【问题标题】:Prevent google script from duplicating protected ranges防止谷歌脚本复制受保护的范围
【发布时间】:2017-07-24 00:48:27
【问题描述】:

我有这个脚本,我用它来复制(将公式转换为值),然后当用户在末尾的某个单元格(A2、A6 等)中输入值“Burned”时保护范围每个月(不能让它按日期触发,因为用户可能在稍微不同的日期完成数据输入)。电子表格需要用户每个月锁定数据,因此设置脚本以在用户每个月输入“Burned”时转换和保护每个月的数据。该脚本可以很好地将公式转换为值,并且还可以保护范围。但是,每次我编辑工作表时,它都会创建重复的受保护范围,因此我最终会得到多个受保护范围,称为 January Burned、February Burned 等。有没有办法防止脚本复制受保护范围?非常感谢任何帮助。

function onEdit(e)
//January
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckA = sheet.getRange("A2").getValue();
var rangeA = sheet.getRange("A2:AZ5");  
{
if(valueToCheckA == "Burned")
{
rangeA.copyTo(rangeA, {contentsOnly:true});
var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
}
}
} 

//February
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckB = sheet.getRange("A6").getValue();
var rangeB = sheet.getRange("A6:AZ9");  
{
if(valueToCheckB == "Burned")
{
rangeB.copyTo(rangeB, {contentsOnly:true});
var protection = rangeB.protect().setWarningOnly(true).setDescription('February Burned');
}
}
} 

//March
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckC = sheet.getRange("A10").getValue();
var rangeC = sheet.getRange("A10:AZ13");  
{
if(valueToCheckC == "Burned")
{
rangeC.copyTo(rangeC, {contentsOnly:true});
var protection = rangeC.protect().setWarningOnly(true).setDescription('March Burned');
}
}
} 

【问题讨论】:

    标签: javascript google-apps-script duplicates range


    【解决方案1】:

    您的代码中发生了一些奇怪的事情。所以我会像这样重新格式化它:

    //January
    function onEdit(e)
    {
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
      var valueToCheckA = sheet.getRange("A2").getValue();
      var rangeA = sheet.getRange("A2:AZ5");  
      if(valueToCheckA == "Burned")
      {
        rangeA.copyTo(rangeA, {contentsOnly:true});
        var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
      }
    } 
    

    再试一次,如果有任何变化,请告诉我。

    再次查看您的代码后。我抓住了整个代码并仔细查看了它,我发现了一个有趣的发现。您的一些代码部分不在 onEdit 函数中,因此即使在未调用 onEdit 时,它们也会在您每次访问脚本时运行。事实上,当我想到它时,我相信你只是每月运行一次,所以为什么不把它放在一个单独的函数中,每月调用一次,然后忘记 onEdit 触发器。

    function onEdit(e)
    {
      var ss = SpreadsheetApp.getActive();//January
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
      var valueToCheckA = sheet.getRange("A2").getValue();
      var rangeA = sheet.getRange("A2:AZ5");  
      if(valueToCheckA == "Burned")
      {
        rangeA.copyTo(rangeA, {contentsOnly:true});
        var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
      }
    } 
    // This section is not in the onEdit function so it's run every time you come to this page
    var ss = SpreadsheetApp.getActive();//February
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
    var valueToCheckB = sheet.getRange("A6").getValue();
    var rangeB = sheet.getRange("A6:AZ9");  
    if(valueToCheckB == "Burned")
    {
        rangeB.copyTo(rangeB, {contentsOnly:true});
        var protection = rangeB.protect().setWarningOnly(true).setDescription('February Burned');
    }
    
    // This section is not in the onEdit function so it's run every time you come to this page 
    var ss = SpreadsheetApp.getActive();//March
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
    var valueToCheckC = sheet.getRange("A10").getValue();
    var rangeC = sheet.getRange("A10:AZ13");  
    if(valueToCheckC == "Burned")
    {
      rangeC.copyTo(rangeC, {contentsOnly:true});
      var protection = rangeC.protect().setWarningOnly(true).setDescription('March Burned');
    }
    

    所以这是一个可以为您完成这项工作的功能的粗略开始,您只需每月运行一次即可。我没有测试它,它很可能有一些错误,所以请检查一下。

    function monthlyBurn()
    {
      var ui = SpreadsheetApp.getUi();
      var response = ui.prompt('Enter checkCell,protectRange,description all separate by commas', ui.ButtonSet.OK);
      var t = response.getResponseText().split(',');
      if(t.length !== 3)
      {
       ui.alert('Invalid input. Your missing a parameter')
       return;
      }
      var ss = SpreadsheetApp.getActive();
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
      var valueToCheckC = sheet.getRange(t[0]).getValue();
      var rangeC = sheet.getRange(t[1]);  
      if(valueToCheckC == "Burned")
      {
        rangeC.copyTo(rangeC, {contentsOnly:true});
        var protection = rangeC.protect().setWarningOnly(true).setDescription(t[2]);
      }
    }
    

    【讨论】:

    • 脚本运行和以前一样,肯定看起来更干净一些。但是,它仍然存在相同的问题,即每当对电子表格进行另一次编辑时,它都会创建一个新的受保护范围。因此,每次进行编辑时都会得到多个受保护的范围。有没有办法编辑脚本,使其只创建一次受保护范围,一旦为该特定范围创建了受保护范围,脚本的该部分将停止运行,因此不再创建任何受保护范围。
    • 我想知道是否可以让两个 onEdit 触发器调用同一个函数,以便它总是被调用两次。
    • 我不确定这会有什么帮助,如果每次编辑总是调用(或调用两次)它,它将继续创建多个受保护的范围。有没有办法获取受保护范围的名称(“January Burned”)并做出“如果不等于”声明,以便如果命名受保护范围,则脚本不会运行?我尝试查找如何执行此操作,但无法正常工作。
    • 我刚刚修改了我的答案。看看吧。
    【解决方案2】:

    感谢所有的意见和帮助,我已经与一位能够编写此脚本的同事进行了交谈,该脚本运行良好。

        function onEdit(e)
    {
      var sheet = e.range.getSheet();
      if (sheet.getName() != "Caseload" || e.value != "Burned") return;
    
      var moment = Moment.load();
      var date = moment.utc(e.range.offset(0, 1).getValue());
      if (!date.isValid()) return;
    
      var month = date.format('MMMM');
      var range = sheet.getRange(e.range.getRow(), e.range.getColumn(), 4, 26*2); // 4 rows and 26*2 columns (AZ)
      range.copyTo(range, {contentsOnly: true});
      range.protect().setWarningOnly(true).setDescription(month + ' Burned');
    

    【讨论】:

      猜你喜欢
      • 2018-04-16
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      相关资源
      最近更新 更多