如何从 Google Sheet 脚本中的 onEdit() 获取旧公式(不是 oldValue)

问题描述 投票:0回答:2

有谁知道是否有办法访问编辑事件对象的旧(即预编辑)公式,而不是 oldValue ?我认为 e.oldFormula 可以工作,但它是未定义的,甚至在文档中也没有。

我正在编写一个脚本,在编辑某些范围时需要密码,但是,为了在用户未能提供正确密码的情况下撤消编辑,我需要知道单元格之前的内容。对于包含数字或字符串的单元格,e.oldValue 效果很好,但我想要保护的大多数单元格都包含公式(这就是我想要保护它们的原因),因此 e.oldValue 会阻止数据更新。

这是我得到的代码,仅当单元格不包含公式时才有效(除此之外,它效果很好:

// Prompt for password before allowing edit of formula cells
function onEdit(e) {
   var ss = SpreadsheetApp.getActiveSpreadsheet();
   var sheet = ss.getActiveSheet();
   var cell = sheet.getActiveCell();
   var editRange = e.range;
   var editCol = editRange.getColumn();


  if (editCol != 4 ) {
    var password = "321"; // not actual password
    var passwordAttempt = Browser.inputBox('Enter Password to edit protected range, or hit cancel to cancel edit:', Browser.Buttons.OK_CANCEL);

    if(passwordAttempt == password) {
      Browser.msgBox('Edit Accepted');
    } else {
      if (passwordAttempt != 'cancel'){
        Browser.msgBox('Incorrect password. Contact James Atkins for password to edit protected ranges.');
      }
      if(e.oldValue){
         Browser.msgBox('old value is defined as ' + e.oldFormula);
         e.range.setValue(e.oldValue);
      } else {
         e.range.clear();
     }
  }
仅供参考,我这样做是因为 Google 表格中的内置受保护范围无法区分用户是通过手动编辑单元格内容还是通过激活更改内容的脚本来更改单元格内容。我想允许所有用户激活对某些范围进行排序和清除的脚本,但不要让他们手动弄乱内容。

javascript google-apps-script google-sheets
2个回答
0
投票
您可以通过创建工作表的克隆来跟踪您的公式来解决此问题。禁止最终用户使用克隆表。所以他们无法编辑它。

function onEdit(e) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getActiveSheet(); var cloneSheet = ss.getSheetByName("cloneSheet") var cell = sheet.getActiveCell(); var editRange = e.range; var cloneRange = cloneSheet.getRange(editRange.getA1Notation()) var editCol = editRange.getColumn(); if (editCol != 4 && sheet.getName() != "cloneSheet") { var password = "321"; // not actual password var passwordAttempt = Browser.inputBox('Enter Password to edit protected range, or hit cancel to cancel edit:', Browser.Buttons.OK_CANCEL); if(passwordAttempt == password) { Browser.msgBox('Edit Accepted'); cloneRange.setValue(editRange.getFormula()) //modify the clone to match the new formula. } else { if (passwordAttempt != 'cancel'){ Browser.msgBox('Incorrect password. Contact James Atkins for password to edit protected ranges.'); } if(e.oldValue){ Browser.msgBox('old value is defined as ' + cloneRange.getFormula()); e.range.setValue(cloneRange.getFormula()); } else { e.range.clear(); } } } }

但是,最终用户仍然可以看到密码。如果您确实希望最终用户只进行有限的更改,那么以下解决方案更好。

替代解决方案

当最终用户执行脚本时,即使您已经编写了脚本,它也会以最终用户的范围/身份运行。因此,如果他们没有编辑权限,那么以其别名运行的脚本也没有编辑权限。这是对您评论的回应:

谷歌表格不区分用户通过手动编辑单元格内容和激活更改内容的脚本来更改单元格内容。

那么如何解决这个问题,您可以使用谷歌网络应用程序来运行排序和清除脚本。最终用户使用一个脚本,该脚本使用 UrlFetch 调用该脚本,这可以解决范围问题并阻止他们查看您的代码/密码等。

这是解决类似问题的问题:

Google Apps 脚本:暂时以其他用户身份运行脚本


0
投票
我没有复制每张工作表,而是创建了一些代码来将电子表格中的所有公式收集在一个名为“公式”的工作表中。从那里我检查受保护的单元格是否包含公式。

希望这有帮助

在工作表公式中,我有以下标题:

A:公式 B: 工作表名称

C:行列
D:工作表公式中的唯一代码行
F:求公式

G:公式中的行

I:求公式

J。公式的行

在单元格 F2 中创建唯一值:

=数组公式(B2:B&C2:C&"_"&D2:D)

工作表公式单元格 G2 中的行: =数组公式(行(B2:B))

在公式单元格 J2 中查找行: =IF(ISERROR(VLOOKUP(I2;formulas!F:G;2;FALSE));"";VLOOKUP(I2;formulas!F:G;2;FALSE))

const SECURITY = true function onEdit(e) { var oldValue = e.oldValue var resultSheetName = ss.getSheetName(); var r = spreadsheet.getActiveCell(); var source_row = r.getRow(); var source_column = r.getColumn() if (SECURITY == true); { Browser.msgBox("This cell may not be changed.") var OldContent = OldFormula(resultSheetName,source_row,source_column,oldValue) r.setValue(OldContent) return; } } // This function is called in onEdit(e) when a protected cell was changed. function OldValueOrFormula (resultSheetName,source_row,source_column,oldValue){ var formula = GetOldFormula(resultSheetName,source_row,source_column) // zet de juiste oude waarde if(formula == ""){ if (oldValue == undefined){ var OldContent = "" } else{ var IsNumber = oldValue.slice(-2); if(IsNumber == ".0") { var OldContent = oldValue.replace(".0","").trim() var OldContent = Number(OldContent) } else { var OldContent = oldValue } } } else{ var OldContent = formula } return OldContent; } // this function checks if there was a formula in the edited cell. function GetOldFormula(Sheetname,Row,Column) var spreadsheet = SpreadsheetApp.getActive(); var ss = SpreadsheetApp.getActive(); { // sheetname, rij, kolom) var SearchKey = Sheetname+Row+"_"+Column ss.getSheetByName("formulas").getRange("I2").setValue(SearchKey) var RowToRead = ss.getSheetByName("Formulas").getRange("J2").getValue() if (RowToRead !== ""){ var formula = ss.getSheetByName("Formulas").getRange("A"+RowToRead).getFormula() } else{ var formula = "" } return formula; } } function AllSheetNames() { let ss = SpreadsheetApp.getActive(); let sheets = ss.getSheets(); let sheetNames = []; sheets.forEach(function (sheet) { sheetNames.push(sheet.getName()); }); return sheetNames; } // this function is to populate the Formulas sheet with all formulas in your spreadheet. function GetFormulas() { var spreadsheet = SpreadsheetApp.getActive(); var ss = SpreadsheetApp.getActive(); var sheetNames = AllSheetNames(); var RowtoWrite = 2 ss.getSheetByName("Formulas").getRange("A2:D").clearContent() var sheetToWrite = ss.getSheetByName(Formulas) for (var i = 0; i < sheetNames.length; i++) { var sheetName = sheetNames[i] if (sheetName !== "Formulas"){ var LastRow = ss.getSheetByName(sheetName).getLastRow() var LastColumn = ss.getSheetByName(sheetName).getLastColumn() var Formulas = ss.getSheetByName(sheetName).getRange(1,1,LastRow,LastColumn).getFormulas() for (var j = 0; j < LastRow; j++) { for (var k = 0; k < LastColumn; k++) { if(Formulas[j][k] !== ""){ var formula = formulas[j][k] var StringToWrite = [sheetName,formula,j,k] ss.getSheetByName("Formulas").getRange("B"+RowtoWrite).setValue(sheetName) ss.getSheetByName("Formulas").getRange("A"+RowtoWrite).setValue(formula) ss.getSheetByName("Formulas").getRange("C"+RowtoWrite).setValue(j+1) ss.getSheetByName("Formulas").getRange("D"+RowtoWrite).setValue(k+1) RowtoWrite = RowtoWrite+1 } } } } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.