【问题标题】:Updating historic Ranges on Add row/column Google App Script在添加行/列 Google App 脚本上更新历史范围
【发布时间】:2020-09-16 11:49:08
【问题描述】:

我知道这对于有经验的 Google App Script 开发人员来说非常简单。我是 Google App Script 的新手,从 2 天开始就开始尝试这个,所以我来到了这里。

让我解释一下这个场景,我们有一个 Google Sheet 插件。当用户使用我们的插件进行一些查询时,我们将查询 id[A column]、Sheet name[B column] 和更新的单元格范围 [C column] 保存在隐藏的工作表中,如图所示。

现在,如果用户从工作表中添加/删除列/行,我们想要更新这些范围。

例如,我们在工作表中有范围 J4:k14。例如,用户在 C 的左侧添加列,然后 J4:K14 范围转移到 K4:L14。

function onChange(e) {
 if (['EDIT', 'INSERT_ROW', 'INSERT_COLUMN', 'REMOVE_ROW', 'REMOVE_COLUMN'].includes(e.changeType)) {
    
    var range = SpreadsheetApp.getActiveRange();
    var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var querySheet = activeSpreadsheet.getSheetByName("OurHiddenSheet");
    // First I want to read C column to get values. that will be assigned in **range**.
    var addresses = Sheets.Spreadsheets.Values.get(querySheet.getSheetId(), range);
    // Since addresses contain all ranges, I can create RangeList from this.
    var rangeList = activeSpreadsheet.getRangeList(addresses);

    // Is there any function available in Google App Script, if the Range was impacted by the operation or not?
    

  }
}

如何读取整个 B 和 C 列并根据当前工作表名称和范围进行过滤?

我想知道,是否有任何功能可以知道范围是否受到操作的影响?

【问题讨论】:

  • 我必须为我糟糕的英语水平道歉。不幸的是,我无法理解Now We want to update these ranges if user add/remove column/row from the sheet. e.g we have range J4:k14 in the sheet. e.g User add column left of C, then the J4:K14 range shift to K14:L14. How to read the entire B and C column and filter based on current sheet name and range?。可以问一下具体情况吗?
  • @Tanaike 抱歉有错误。更新后的范围为 K4:L14。位于位置 J4:K14 的数据,由于在 C 处添加列,新位置将是 K4:L14
  • 感谢您的回复。我不得不再次为我糟糕的英语水平道歉。不幸的是,从您更新的问题来看,我仍然无法理解您当前的脚本问题和目标。特别是,我无法想象e.g we have range J4:k14 in the sheet. e.g User add column left of C, then the J4:K14 range shift to K4:L14. How to read the entire B and C column and filter based on current sheet name and range?的情况。
  • 打开一张表 把一些数据放在 D2:E2 范围内。在 C 列左侧添加一列。我们添加的数据 D2:E2 范围,它的新位置是 E2:F2 。
  • 感谢您的回复。我不得不再次为我糟糕的英语水平道歉。很遗憾,我无法理解Open a sheet Put some data in D2:E2 range. Add a column left to C column. The data which we added D2:E2 range, it's new position is E2:F2 . 与您的图片和脚本之间的关系。

标签: google-apps-script google-sheets


【解决方案1】:

更好的方法是将数据存储为developerMetadata。例如,对于第一行数据(NewSheet!J4:K14),您可以将元数据存储在 NewSheet!4:4 行和 NewSheet!J:J 列中,其中key 可以是查询 uuid,value 是行数(10)和列数(2)。

见:

【讨论】:

  • @ThaMaster 感谢您对 developerMetaData 的建议,但 30000 个字符的限制会给我们带来问题。随着用户在我们的插件中执行的每个操作,我们将存储更多数据。
  • @jagad89 然后像我展示的那样存储范围引用。将其余部分存储在隐藏的工作表中。还有,每张是 30k+30k
  • 我们更新了我们的方法。当我们生成任何范围时,我们为其命名。并设置公式从该命名范围获取工作表名称和范围。因此,每当用户执行操作时,namedrange 都会更新并反映在我们的查询日志表中。
  • @jagad89 随时添加答案。
【解决方案2】:

解决方案

没有内置函数可以让您知道范围是否受到影响。但是您可以轻松构建碰撞​​检测器算法,因为它是一个简单的 2D 空间:

/**
 * Detects the collision between to ranges specified in A1 Notation
 *
 * @param {string} a - The first range in A1 Notation.
 * @param {string} b - The second range in A1 Notation.
 *
 * @returns {boolean} - true if the two ranges overlaps false otherwise
 */
function collision(a,b) {
  var _a = SpreadsheetApp.getActiveSpreadsheet().getRange(a);
  var _b = SpreadsheetApp.getActiveSpreadsheet().getRange(b);
  
  var _ax = _a.getColumn();
  var _ay = _a.getRow();
  var _awidth = _a.getLastColumn() - _ax;
  var _aheight = _a.getLastRow() - _ay;
  
  var _bx = _b.getColumn();
  var _by = _b.getRow();
  var _bwidth = _b.getLastColumn() - _bx;
  var _bheight = _b.getLastRow() - _by;
  
  return _ax < _bx + _bwidth && _ax + _awidth > _bx && _ay < _by + _bheight && _ay + _aheight > _by;
}

使用此函数,您可以构建一个switch case,它根据Event type、重叠和活动范围坐标更新您的范围引用。

例如,在“INSERT_COLUMN”的情况下,您可以这样更新:

   var values;
   switch(e_type) {
     case "INSERT_COLUMN":
       values = querySheet.getRange("A2:C2")
                .getValues()
                .map((row) => {
                     let r = querySheet.getRange(row[2]);
                     // If the active range is outside our rangelist we don't have to update
                     if (row[1] == sheetName && range.getColumn() < r.getLastColumn()) {
                          let width = range.getLastColumn() - range.getColumn() + 1;
                          // When overlapping you should check where the active range start wither to offset the whole range or to extend its width.
                          if (collision(row[2], range.getA1Notation())) {
                                 if (range.getColumn() <= r.getColumn()) {
                                        row[2] = getShiftOffsetColumn(r, width);
                                 } else {
                                        row[2] = getShiftExtendedColumn(r, width);
                                 }
           
                           } else {
                                 // No collision, just offset.
                                 row[2] = getShiftOffsetColumn(r, width);
                           }
                     }
                     return row;
       });
       
       break;
     case "REMOVE_COLUMN":

       [...]
     
     default:
       // Exception handling
   }
   querySheet.getRange("A2:C2").setValues(values); //updates the values in hidden sheet

[...]

// --- Support functions ---

// This function handles the offset
function getShiftOffsetColumn(r, width) {
   return SpreadsheetApp.getActiveSheet().getRange(r.getRow(), r.getColumn() + width, r.getLastRow() - r.getRow() + 1, r.getLastColumn() - r.getColumn() + width).getA1Notation();
}

// This function handles the extension
function getShiftExtendedColumn(r, width) {
  return SpreadsheetApp.getActiveSheet().getRange(r.getRow(), r.getColumn(), r.getLastRow() - r.getRow() + 1, r.getLastColumn() - r.getColumn() + 1 + width).getA1Notation();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    相关资源
    最近更新 更多