Проблема
Лист, на который ссылается 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 не существует метода, который мог бы напрямую вернуть лист по его идентификатору, вы можете получить нужный лист следующим образом:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheets = ss.getSheets();
const id = "ID here";
const targetSheet = sheets.find(sheet => sheet.getSheetId() === id);
И найти идентификатор листа, чтобы избежать жесткого кодирования (образец относится к текущему активному листу) вы можете использовать getSheetId()
метод:
const sh = SpreadsheetApp.getActiveSheet();
const id = sh.getSheetId();