#javascript #google-apps-script #google-sheets #indexof
#javascript #google-apps-script #google-sheets #indexof
Вопрос:
Я записываю простой код для перебора всех ссылок в диапазоне, сбора информации из этих электронных таблиц (ссылок) и вставки в текущую строку цикла.
function UpdateProjects()
{
//----------EDIT THIS FOR A DIFFERENT CLIENT-------------
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Projects");
var etilastrow = sheet.getLastRow();
var urlRange = sheet.getRange(2, 1, etilastrow);
var urlsvalues = urlRange.getValues();
var urls = urlRange.getFormulas();
Logger.log(urls)
//looping through all of the rows
for (var i = 0; i < etilastrow; i) {
currentRow = 2 i;
var dirturl = urls[i];
var remove_before = dirturl[i].indexOf('",');
var url = dirturl[i].substring(12, remove_before);
Logger.log(currentRow);
Logger.log(url);
//-----------------Loop code below until last project-------
var projectPCBdesignsheet = SpreadsheetApp.openByUrl(url).getSheetByName("Main");
var lstrow = projectPCBdesignsheet.getLastRow();
const vA=projectPCBdesignsheet.getRange(7,2,lstrow).getValues();//get data from project's PCB Design sheet
//add last edit values
sheet.getRange(currentRow, 4).setValue(vA[10]);
sheet.getRange(currentRow, 5).setValue(vA[11]);
//additional data from PCB design sheet
sheet.getRange(currentRow, 6).setValue(vA[0]);
sheet.getRange(currentRow, 7).setValue(vA[1]);
sheet.getRange(currentRow, 8).setValue(vA[2]);
sheet.getRange(currentRow, 9).setValue(vA[3]);
sheet.getRange(currentRow, 11).setValue(vA[5]);
}
}
Скрипт работает, если я жестко закодирую URL-адрес в переменную. Прямо сейчас, из журнала, я вижу номер строки и чистый URL.
Проблема в том, что скрипт останавливается с этой ошибкой: «Ошибка типа: не удается прочитать свойство ‘indexOf’ неопределенного ETIUpdateProjects @ UpdateProjects.gs:18»
Я не понимаю, как он может найти ошибку в строке 18, если он показывает мне журнал currentRow и url, которые идут после строки «indexOf».
Комментарии:
1.
etilastrow
не следует использовать таким образом, потому что вы начинаете получать строки со 2-го, а не с 1-го, можете ли вы вычесть из него и посмотреть, поможет ли это?
Ответ №1:
Проблемы:
Проблема 1:
Начиная со второй строки, вы получаете одну дополнительную пустую ячейку в данных:
var urlRange = sheet.getRange(2, 1, etilastrow);
это даст вам что-то вроде: [[=link],['']]
это можно исправить, изменив etilastrow
на etilastrow-1
.
и то же самое в for
цикле.
Проблема 2:
Даже если вы исправите проблему 1, основная проблема в текущем коде, которая также вызывает ошибку, которую вы получаете, находится в этих строках:
var dirturl = urls[i];
var remove_before = dirturl[i].indexOf('",');
Помните, urls
что это массив etilastrow
строк, но только один столбец. Если вы перефразируете свой код, то то, что вы вызываете, по сути urls[i][i]
. Это вернется undefined
после второй итерации, когда i
станет 1
, потому что в данных есть только один столбец.
Причина, по которой ваш код работает, заключается в том, что вы тестируете его с заполненной одной ячейкой и, следовательно urls[0][0]
, работает правильно, но если вы добавите больше URL-адресов, второй индекс увеличится до более чем 0
, и это, например urls[0][1]
, приведет к удалению и ошибке, потому urls
что имеет только один столбец.
Чтобы решить эту проблему, вы могли бы изменить:
var dirturl = urls[i];
var remove_before = dirturl[i].indexOf('",');
var url = dirturl[i].substring(12, remove_before);
Для:
var dirturl = urls[i];
var remove_before = dirturl[0].indexOf('",');
var url = dirturl[0].substring(12, remove_before);
Улучшения:
Улучшение 1:
Я бы посоветовал вам ознакомиться с for
циклами, потому что они могут сбивать с толку при работе с индексами и массивами, и вам нужно быть достаточно удобным для их обработки. Используйте forEach и flat() для прямой работы с каждым URL-адресом:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Projects");
var etilastrow = sheet.getLastRow();
var urlRange = sheet.getRange(2, 1, etilastrow-1);
var urlsvalues = urlRange.getValues();
var urls = urlRange.getFormulas();
urls.flat().forEach((r,i)=>{
let currentRow = i 2;
let remove_before = r.indexOf('",');
let url = r.substring(12, remove_before);
console.log(url)
console.log(currentRow)
// put here the rest of your code
})
Улучшение 2:
С точки зрения Google Apps Script setValue
многократный вызов, но также и в for
цикле, может стоить большой производительности. Согласно рекомендациям, правильный способ сделать это — сохранить значения в массиве, а затем использовать setValues
вместо этого вне цикла for. Таким образом, вы используете только setValues
один раз.
Я мог бы попытаться оптимизировать эту часть вашего кода, но ответ не будет достаточно полезным, потому что уже есть много сообщений об этой оптимизации, но также ваш код должен работать с исправлениями, которые я указал.
Комментарии:
1. Мариос, большое спасибо за вашу помощь и за то, что вы выделили для этого некоторое время. Я внес некоторые изменения в соответствии с вашими советами, а также обновил setValue одним setValues. Скрипт работает быстро и хорошо. Есть небольшая проблема: цикл forEach не завершится, пока не найдет пустую ячейку без URL. Это через «недопустимый аргумент: url». Я заметил, что невозможно вернуть, прервать или продолжить цикл такого типа, поэтому я полагаю, что это невозможно решить с помощью if (url == «»). Еще раз спасибо за вашу поддержку. Действительно, действительно ценится.
2. К вашему сведению, я также пытался запустить этот скрипт, когда пользователь выбирает этот конкретный лист (информация будет обновляться, когда это необходимо). Мои базовые навыки работы с GAS приводят к такому сценарию, который, к сожалению, не работает. функция onSelectionChange(e) { // Запуск сценария обновления при выборе листа var sheet = e.sheet; var ssname = SpreadsheetApp.getActiveSheet().getName(); if(ssname === «Projects») { UpdateProjects(); } }
3. @Andre8426 рад, что ваша проблема была решена.
forEach
завершится в конце массива. Если вы не хотите завершать работу до этого, я боюсь, вам нужно использоватьfor
цикл. С точки зрения производительности вы ничего не теряете с циклом for, поэтому, если вы хотитеbreak
илиcontinue
мой совет — продолжать использовать цикл for.4. @Andre8426 Я бы посоветовал вам опубликовать новый вопрос относительно модификации. Stackoverflow не допускает последующих вопросов. Извините за неудобства.