我一直在谷歌的几个脚本中发现这个错误,直到过去的一周我才遇到过这个问题。我没有改变我的脚本。
function importData2() {
var sourceSpreadsheetID = "source spreadsheet ID";
var sourceWorksheetName = "Lewis Ford of Dodge City - Flow";
var targetSpreadsheetID = "target spreadsheet ID";
var targetWorksheetName = "forddodgecity";
var thisSpreadsheet = SpreadsheetApp.openById(sourceSpreadsheetID);
var thisWorksheet = thisSpreadsheet.getSheetByName(sourceWorksheetName);
var thisData = thisWorksheet.getDataRange().getValues();
var toSpreadsheet = SpreadsheetApp.openById(targetSpreadsheetID);
var toWorksheet = toSpreadsheet.getSheetByName(targetWorksheetName);
toWorksheet.clearContents();
toWorksheet.getRange(1, 1, thisData.length, thisData[0].length).setValues(thisData);
}
发布于 2020-06-20 06:50:43
问题
sourceWorksheetName
引用的工作表被重命名,导致getSheetByName()
返回null
解决方案
有很多方法可以防止这种情况发生,以下是两种最常见的方法--侵入性和非侵入性:
禁止重命名纸张
这里有一个非常复杂的解决方案,它可以在用户之间持久存在。应该安装为onChange
触发器才能工作。这两个函数中的第一个是简化属性创建和检索的实用程序。
还请注意,您应该运行它至少一次,它才能正确地生效。
/**
* @summary updates current spreadsheet structure
* @param {GoogleAppsScript.Spreadsheet.Spreadsheet} spread
* @param {GoogleAppsScript.Properties.Properties} propStore
* @param {string} propName
* @returns {string}
*/
const updatePersistedStructure = (spread, propStore, propName) => {
const info = {
sheets: spread.getSheets().map(sheet => {
return {
id: sheet.getSheetId(),
name: sheet.getSheetName()
};
})
};
const stringified = JSON.stringify(info);
propStore.setProperty(propName, stringified);
return stringified;
};
/**
*
* @param {GoogleAppsScript.Events.SheetsOnChange} e
*/
function stopSheetRenaming(e) {
const { changeType } = e;
if (changeType === "OTHER") {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const propName = "structure";
//get persisted structure or initialize it;
const store = PropertiesService.getDocumentProperties();
let savedStructure = store.getProperty(propName) || updatePersistedStructure(ss, store, propName);
const { sheets } = JSON.parse(savedStructure);
const currentSheets = ss.getSheets();
let renamedInfo = null, renamedSheet = null;
const sheetRenamed = sheets.some((sheetInfo) => {
const { id, name } = sheetInfo;
const currentSheet = currentSheets.find(sheet => sheet.getSheetId() === id);
const removed = currentSheet === undefined;
if (removed) {
return false; //we don't care about removed sheets;
}
const currentName = currentSheet.getSheetName();
const isRenamed = currentName !== name;
if (isRenamed) {
renamedSheet = currentSheet;
renamedInfo = Object.assign(sheetInfo, { newName: currentName });
}
return isRenamed;
});
if (sheetRenamed) {
const { name, newName } = renamedInfo;
renamedSheet.setName(name);
const ui = SpreadsheetApp.getUi();
ui.alert(`Sheet renaming is forbidden.\n\nTried to rename ${name} to ${newName}`);
}
updatePersistedStructure(ss, store, propName);
}
}
按Id引用工作表
另一个限制较少的解决方案是避免通过可以任意更改的内容引用工作表。虽然由于未知的原因,ATTOW没有任何方法可以通过其ID直接返回工作表,但您可以获得如下所需的工作表:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheets = ss.getSheets();
const id = "ID here";
const targetSheet = sheets.find(sheet => sheet.getSheetId() === id);
要找到工作表Id以避免硬编码(示例涉及当前活动的工作表),可以使用getSheetId()
方法:
const sh = SpreadsheetApp.getActiveSheet();
const id = sh.getSheetId();
https://stackoverflow.com/questions/62472662
复制相似问题