TypeError: невозможно прочитать свойство getDataRange, равное null, для триггера - PullRequest
0 голосов
/ 19 июня 2020

Я продолжаю получать эту ошибку в нескольких моих скриптах Google и никогда не сталкивался с этой проблемой до прошлой недели. Я не менял свои скрипты.

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); 
}

1 Ответ

0 голосов
/ 20 июня 2020

Проблема

Лист, на который ссылается 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...