使用App Script在许多电子表格上执行一次功能

时间:2015-01-06 04:34:53

标签: google-apps-script google-sheets normalize

我希望运行一个Google脚本,在一个(30多个)Google表格上标准化一个小区范围。或者更准确地说,我希望(技术较少的)用户能够做到这一点。我似乎找不到合理的工作流程。

我能看到的选项是:

将脚本作为绑定脚本复制/粘贴到每个电子表格

这很麻烦,因为那时脚本有很多副本,通常不会再次运行,而且还有很多开销和点击来为每一个安装宏。

使用库

我可以将代码的主体放在库中,然后复制/粘贴只是一个存根(就像接受的答案here)。

然而,这对于用户体验仍然同样糟糕,加上各种报道库都很难处理。

制作附加组件

“正确的方法”似乎是创建一个用户可以为每个电子表格启用的附加组件。但是,附加组件似乎仍处于“开发人员预览”模式,授权周期不确定且可能很慢。谷歌还希望该脚本已经过多个活跃用户的测试。这很难 - 当我对它进行彻底的测试时,这个工作基本上就完成了。如何在不发布插件的情况下测试它呢?

其他选择?

还有其他方法,也许使用非绑定脚本?由于需要一些用户输入(电子表格中的范围等),因此无法运行单个脚本并使其迭代所有电子表格。

有没有办法让用户可以安装未绑定的脚本,运行它,然后它会询问运行它的电子表格?

openByUrl()非常接近,但实际上并没有打开电子表格用户界面,因此我无法使用getActiveRange()等功能。

如果它是相关的,这是脚本:

/*function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Normalize')
      .addItem('Normalize Crosstab', 'normalizeCrossTab')
      .addToUi();
}*/

function onOpen() {
  var ss = SpreadsheetApp.getActive();
  var items = [
    {name: 'Normalize Crosstab', functionName: 'normalizeCrosstab'},
  ];
  ss.addMenu('Normalize', items);
}

/* Converts crosstab format to normalized form. Given columns abcDE, the user puts the cursor somewhere in column D.
The result is a new sheet, NormalizedResult, like this:

a     b     c    Field Value
a1    b1    c1   D     D1
a1    b1    c1   E     E1
a2    b2    c2   D     D2
a2    b2    c2   E     E2
...

*/
function normalizeCrosstab() {
  var sheet = SpreadsheetApp.getActiveSheet(); 
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();
  var values = rows.getValues();
  var firstDataCol = SpreadsheetApp.getActiveRange().getColumn();
  var dataCols = values[0].slice(firstDataCol-1);

  if (Browser.msgBox("This will create a new sheet, NormalizedResult. Place your cursor is in the first data column.\\n\\n" +
                     "These will be your data columns: " + dataCols,Browser.Buttons.OK_CANCEL) == "cancel") {
    return;
  }


  var resultssheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NormalizedResult");
  if (resultssheet != null) {
    SpreadsheetApp.getActive().deleteSheet(resultssheet);
  }
  var header = values[0].slice(0, firstDataCol - 1);

  var newRows = [];

  header.push("Field");
  header.push("Value");
  newRows.push(header);

  for (var i = 1; i <= numRows - 1; i++) {
    var row = values[i];
    for (var datacol = 0; datacol < dataCols.length; datacol ++) {
      newRow = row.slice(0, firstDataCol - 1); // copy repeating portion of each row
      newRow.push(values[0][firstDataCol - 1 + datacol]); // field name
      newRow.push(values[i][firstDataCol - 1 + datacol]); // field value
      newRows.push(newRow);
    }
  }
  var newSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("NormalizedResult");
  var r = newSheet.getRange(1,1,newRows.length, header.length);
  r.setValues(newRows);
};

2 个答案:

答案 0 :(得分:1)

您可以检索用户提供URL的工作表,用简单的HTML展示它们,在另一个工作表下面一个工作表,然后附加一个按钮列,它将为该ROW调用normalizeCrosstab()。这是一个已发布的HTML解决方案,任何人都可以在不登录的情况下使用。

如果有定义数量的工作表,您也可以使用名称旁边的按钮在HTML中生成它们,它将生成TABLE HTML。

或者使用图书馆,我怀疑你有什么需要和不能做的,答案很老(12')。

我正在使用图书馆并且没有任何问题,对所有事情都非常方便,所有工作表必须具有这3个功能才能像脚本本身一样工作:

function onOpen() {
  library.onInitialize();
}

function onEdit(celEd) {
  library.onMakeEdit(celEd);
}

function libraryFuncs( funcName, args ){ // Needed for sideBars to use library functions
  if(args)
    args = args.split("\!|"); // Predefined separation of args
  else
    args = [];

  return library[ funcao ]().apply(this, args);
}

答案 1 :(得分:1)

第一个问题是:&#34;谁是这些床单的所有者?&#34;如果是所有这些工作表的所有者,则您有权远程访问它们。如果您不拥有它们,则所有者需要共享,并为尝试修改其文件的任何代码授予编辑权限。

如果您拥有所有电子表格,则可以创建一个独立应用程序从中心点执行所有处理。然后,您只需将Stand Alone App的链接通过电子邮件发送给每个人,或让每个用户在其电子表格中输入一个链接到Stand Alone App。正如您所提到的,对于该选项,您无法使用getActiveSheet()等方法。

无论您使用何种选项,您都需要让人们在其电子表格中添加内容,或者创建一些新的集中式界面。您最好的选择可能归结为所有权和设置权限。

我猜测如果电子表格的用户是所有者,并且不想给你许可,他们就需要使用前三个选项中的一个。我首先从图书馆开始。

如果您可以轻松获取电子表格的文件ID,则可以创建一个将用户与FileID匹配的对象。

var objUserToFileID = {"user1":"abc34ciu89384u", "user2":"FileID_Two", "user3":"FileID_Three"};

然后让用户从列表中选择他们的名字,(下拉列表)然后运行代码。这是Stand Alone App的用武之地。当然,如果用户为其他人的电子表格选择fileID,您需要弄清楚会发生什么。然后,您需要有办法确定应用程序的用户是谁。