如何为使用 appendRow 写入数据的多个复选框制作更好的 Google Sheets 循环脚本
How to make a better Google Sheets looping script for multiple checkboxes that write data using appendRow
我想看看是否有比我从其他 S.O 拼凑出来的更有效的编码选项。职位。我对 Sheets 编码非常缺乏经验,所以我确定我已经找到了效率最低的解决方案。我不太了解缓存的使用或其他实践。
我有一页数据搜索结果(下面称为 GammaPage),这些结果是根据用户搜索填充的。当用户找到他们想要合并到单独报告中的一行数据时,他们按下一个复选框,然后该复选框触发一个 onEdit(e) 命令,该命令将所选数据行(并且仅该行)附加到用于数据收集和处理的单独页面(下面的 EpsilonPage)。
什么有效:脚本 运行正确,在复选框提示时导出用户选择的数据。
令我疑惑的是:脚本需要很长时间才能运行(大约8秒)。我觉得在执行相同任务时必须有一种更有效的方法来编写它。需要说明的是,我并不是要全新的剧本。我只是问是否应该以某种方式重写我拥有的那个,以便更干净地循环。
为什么会这样:
- 脚本需要将所选数据的每个新行追加到前一个选择的下方一行。
- 数据必须是静态值,而不是可以更改的值,因此任何基于代码的解决方案(如 QUERY 或 IMPORTRANGE)都不起作用。
- 需要支持 30 个单独的复选框,允许用户选择 30 个搜索结果(当他们检查原始数据时)中的任何一个来导出。
- 代码的执行需要在用户点击复选框时发生;基于时间的触发器是不够的。
代码(为清楚起见进行了压缩): 我在下面附加了函数,或者至少附加了它的前四个循环,以演示它是如何工作的。整个函数目前 341 行长 。我觉得我好像错过了一个明显的通配符。
function onEdit(e) {
if (e.source.getActiveSheet().getName() != 'AlphaSheet' && != 'BetaSheet' && e.source.getActiveSheet().getName() != 'EpsilonSheet') {
var spreadsheet = SpreadsheetApp.getActive();
var rr = e.range;
var ss = e.range.getSheet();
var headerRows = 5; // # header rows to ignore
if (rr.getRow() <= headerRows) return;
var checkBoxLocation6 = "A6";
const values6 = spreadsheet.getRange('GammaSheet!B6:D6').getValues().flat();
var checkBoxLocation7 = "A7";
const values7 = spreadsheet.getRange('GammaSheet!B7:D7').getValues().flat();
var checkBoxLocation8 = "A8";
const values8 = spreadsheet.getRange('GammaSheet!B8:D8').getValues().flat();
var checkBoxLocation9 = "A9";
const values9 = spreadsheet.getRange('GammaSheet!B9:D9').getValues().flat();
var checkBoxCondition = true;
var result = SpreadsheetApp.getUi().alert("Do you wish to extract this data?", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('GammaSheet'), true);
if (e.range.getA1Notation() == checkBoxLocation6) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values6);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A6').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation7) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values7);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A7').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation8) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values8);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A8').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation9) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values9);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A9').setValue('FALSE');}}
}};
以此类推另外26个循环
截图供参考:
那么,考虑到我想要它做的事情,我的编码可以不那么笨拙吗?还是说它已经很好了?
抱歉,实在是忍不住想把314行改成25行(无注释)。那么,我们开始吧:
function onEdit(e) {
// check if it's first column
if (e.range.columnStart != 1) return;
// check if checkbox is true
if (e.value != 'TRUE') return;
// check if the sheet is the right sheet
var sheet = SpreadsheetApp.getActive();
var ignored_sheets = ['BetaSheet', 'EpsilonSheet', 'Imported master list'];
if (ignored_sheets.includes(sheet.getName())) return;
// get data from current row
var row_index = e.range.rowStart;
var row = sheet.getRange('B' + row_index + ':D' + row_index).getDisplayValues().flat();
// check if cell 'C' of current row is not empty, just to be sure
if (row[1] == '') return;
// show the prompt message
var result = SpreadsheetApp.getUi()
.alert("Do you wish to request this student?", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if (result != SpreadsheetApp.getUi().Button.OK) {
sheet.toast("Request canceled.");
return;
}
// do stuff
sheet.toast("Request initiated.");
sheet.getActiveCell().setValue(false);
sheet.getRange('B3').clearContent();
sheet.getSheetByName('EpsilonSheet').appendRow(row);
}
我想看看是否有比我从其他 S.O 拼凑出来的更有效的编码选项。职位。我对 Sheets 编码非常缺乏经验,所以我确定我已经找到了效率最低的解决方案。我不太了解缓存的使用或其他实践。
我有一页数据搜索结果(下面称为 GammaPage),这些结果是根据用户搜索填充的。当用户找到他们想要合并到单独报告中的一行数据时,他们按下一个复选框,然后该复选框触发一个 onEdit(e) 命令,该命令将所选数据行(并且仅该行)附加到用于数据收集和处理的单独页面(下面的 EpsilonPage)。
什么有效:脚本 运行正确,在复选框提示时导出用户选择的数据。
令我疑惑的是:脚本需要很长时间才能运行(大约8秒)。我觉得在执行相同任务时必须有一种更有效的方法来编写它。需要说明的是,我并不是要全新的剧本。我只是问是否应该以某种方式重写我拥有的那个,以便更干净地循环。
为什么会这样:
- 脚本需要将所选数据的每个新行追加到前一个选择的下方一行。
- 数据必须是静态值,而不是可以更改的值,因此任何基于代码的解决方案(如 QUERY 或 IMPORTRANGE)都不起作用。
- 需要支持 30 个单独的复选框,允许用户选择 30 个搜索结果(当他们检查原始数据时)中的任何一个来导出。
- 代码的执行需要在用户点击复选框时发生;基于时间的触发器是不够的。
代码(为清楚起见进行了压缩): 我在下面附加了函数,或者至少附加了它的前四个循环,以演示它是如何工作的。整个函数目前 341 行长 。我觉得我好像错过了一个明显的通配符。
function onEdit(e) {
if (e.source.getActiveSheet().getName() != 'AlphaSheet' && != 'BetaSheet' && e.source.getActiveSheet().getName() != 'EpsilonSheet') {
var spreadsheet = SpreadsheetApp.getActive();
var rr = e.range;
var ss = e.range.getSheet();
var headerRows = 5; // # header rows to ignore
if (rr.getRow() <= headerRows) return;
var checkBoxLocation6 = "A6";
const values6 = spreadsheet.getRange('GammaSheet!B6:D6').getValues().flat();
var checkBoxLocation7 = "A7";
const values7 = spreadsheet.getRange('GammaSheet!B7:D7').getValues().flat();
var checkBoxLocation8 = "A8";
const values8 = spreadsheet.getRange('GammaSheet!B8:D8').getValues().flat();
var checkBoxLocation9 = "A9";
const values9 = spreadsheet.getRange('GammaSheet!B9:D9').getValues().flat();
var checkBoxCondition = true;
var result = SpreadsheetApp.getUi().alert("Do you wish to extract this data?", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('GammaSheet'), true);
if (e.range.getA1Notation() == checkBoxLocation6) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values6);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A6').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation7) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values7);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A7').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation8) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values8);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A8').setValue('FALSE');}}
if (e.range.getA1Notation() == checkBoxLocation9) {
if (e.range.getValue() == checkBoxCondition) {
if(result === SpreadsheetApp.getUi().Button.OK) {
spreadsheet.getSheetByName('EpsilonSheet').appendRow(values9);
SpreadsheetApp.getActive().toast("Request initiated.");
spreadsheet.getRange('B3').clearContent();
} else {
SpreadsheetApp.getActive().toast("Request canceled.");}
spreadsheet.getRange('A9').setValue('FALSE');}}
}};
以此类推另外26个循环
截图供参考:
那么,考虑到我想要它做的事情,我的编码可以不那么笨拙吗?还是说它已经很好了?
抱歉,实在是忍不住想把314行改成25行(无注释)。那么,我们开始吧:
function onEdit(e) {
// check if it's first column
if (e.range.columnStart != 1) return;
// check if checkbox is true
if (e.value != 'TRUE') return;
// check if the sheet is the right sheet
var sheet = SpreadsheetApp.getActive();
var ignored_sheets = ['BetaSheet', 'EpsilonSheet', 'Imported master list'];
if (ignored_sheets.includes(sheet.getName())) return;
// get data from current row
var row_index = e.range.rowStart;
var row = sheet.getRange('B' + row_index + ':D' + row_index).getDisplayValues().flat();
// check if cell 'C' of current row is not empty, just to be sure
if (row[1] == '') return;
// show the prompt message
var result = SpreadsheetApp.getUi()
.alert("Do you wish to request this student?", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if (result != SpreadsheetApp.getUi().Button.OK) {
sheet.toast("Request canceled.");
return;
}
// do stuff
sheet.toast("Request initiated.");
sheet.getActiveCell().setValue(false);
sheet.getRange('B3').clearContent();
sheet.getSheetByName('EpsilonSheet').appendRow(row);
}