Хорошо, полный новичок здесь ... Я искал и нашел различные сценарии «копировать строку на другой лист», но могу заставить работать только один. Вот моя версия ниже. Что я пытаюсь сделать, так это иметь передний лист, на котором отображаются строки из листа 1, где выполняется один из трех критериев, т.е. столбец N имеет статус «Редактировать», «Редактировать SB» или «Изменить редактирование». Приведенное ниже делает это, но оно не зацикливается, и каждый раз, когда я его запускаю, оно повторяет действие, и я получаю дубликаты всех строк на целевом листе. По сути, я хочу, чтобы он работал таким образом, чтобы каждый раз, когда статус столбца N для конкретной строки изменялся на одно из этих трех значений, он отображался на листе 2. Таким образом, лист 2 представляет собой «живое» отображение всех строк на листе 1. где столбец N равен указанному значению
Любая помощь очень ценится...
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1'); //source sheet
var testrange = sheet.getRange('N:N');
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('Sheet 2'); //destination sheet
var data = [];
var j =[];
//Condition check in N:N; If true copy the same row to data array
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Edit') {
data.push.apply(data,sheet.getRange(i+1,1,1,15).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Amend Edit') {
data.push.apply(data,sheet.getRange(i+1,1,1,15).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'SB Edit') {
data.push.apply(data,sheet.getRange(i+1,1,1,15).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
//Delete matched rows in source sheet
//for (i=0;i<j.length;i++){
//var k = j[i]+1;
//sheet.deleteRow(k);
//Alter j to account for deleted rows
//if (!(i == j.length-1)) {
//j[i+1] = j[i+1]-i-1;
}
Если вы хотите, чтобы эта копия происходила при изменении столбца N, вероятно, лучше всего установить триггер, например onEdit. Это даст вам объект с данными о произошедшем событии, включая измененную ячейку и ее значение.
Затем вы можете использовать эти данные, чтобы получить всю строку и скопировать ее на другой лист, например:
function onEdit(e) {
const statuses = ['Edit', 'SB Edit', 'Amend Edit'];
// Check if the modification happened on column N (14th column) and if the new value is one of the desired statuses
if (e.range.getColumn() === 14 && statuses.includes(e.value)) {
// Get sheets
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet1 = spreadsheet.getSheetByName('Sheet1');
const sheet2 = spreadsheet.getSheetByName('Sheet2');
// Get the whole row of the modified cell
const modifiedRow = sheet1.getRange(e.range.getRow(), 1, 1, sheet1.getLastColumn()).getValues();
// Append modified row to the end of Sheet2
sheet2.appendRow(modifiedRow.flat());
}
}
Если вы хотите избежать дублирования строк в Sheet2, вам нужно иметь способ проверить, была ли определенная строка добавлена в Sheet2 ранее.
Например, если столбец A имеет уникальный идентификатор (ID) для строк, вы можете найти этот идентификатор на Листе2 перед добавлением новой строки. Если он существует, вы можете заменить его новыми значениями или просто ничего не делать. Если он не существует, вы добавляете строку в конец:
function onEdit(e) {
// Check if the modification happened on column N (14th column) and if the new value is one of the desired statuses
if (e.range.getColumn() === 14) {
// Specify update statuses
const addStatuses = ['Edit', 'SB Edit', 'Amend Edit'];
const removeStatuses = ['On Hold', 'Version Returned'];
// Get sheets
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet1 = spreadsheet.getSheetByName('Sheet1');
const sheet2 = spreadsheet.getSheetByName('Sheet2');
// Get the whole row of the modified cell
const modifiedRow = sheet1.getRange(e.range.getRow(), 1, 1, sheet1.getLastColumn()).getValues();
// Assume that ID is in column A (first column)
const modifiedRowID = modifiedRow[0][0];
// Get values from Sheet2
const columnValues = sheet2.getDataRange().getValues();
// Check if Sheet2 already has row based on the value of column A and retrieve its index
let rowIndex = -1;
for (let i = 0; i < columnValues.length; i++) {
if (columnValues[i][0] == modifiedRowID) {
rowIndex = i + 1; // JavaScript arrays indices start from 0, but Sheets row indices start from 1
break;
}
}
// If row should be added/removed to/from Sheet2
if (addStatuses.includes(e.value)) {
if (rowIndex == -1) {
// Row not found in Sheet2, so add it
sheet2.appendRow(modifiedRow.flat());
} else {
// Optional: Row found in Sheet2, so replace it with current values
sheet2.getRange(rowIndex, 1, 1, modifiedRow[0].length).setValues(modifiedRow);
}
} else if (removeStatuses.includes(e.value) && rowIndex > -1) {
// Remove row from Sheet2
sheet2.deleteRow(rowIndex);
}
}
}
Это потому, что вы, вероятно, пытаетесь запустить функцию из редактора, но, поскольку это триггер, он вызывается автоматически при каждом изменении листа. Как вы планируете выполнять эту функцию, вручную из редактора или позволить ей выполняться как автоматический триггер?
Ааа..... это снова выдвинет на первый план мою нубность :) В идеале, автоматический триггер был бы замечательным Еще раз, спасибо, что развлекли мою неумелость, когда дело доходит до этого. Последнее кодирование, которое я делал в рамках своей инженерной степени, включало турбо-паскаль :)
Не беспокойтесь :) Если вы хотите использовать его в качестве триггера, вам просто нужно включить его в свой Code.gs и сохранить. Всякий раз, когда лист редактируется, функция onEdit() будет вызываться автоматически. Вот лист, который я использовал для тестирования: docs.google.com/spreadsheets/d/…
Понял, понял, как теперь работает триггер. Да, это работает блестяще. Но есть одна оплошность с моей стороны, которую я не продумал. Они отслеживают анимационные проекты, и в проекты будут внесены поправки. Это ДОБАВЛЯЕТ живые проекты, но не УДАЛЯЕТ неживые. Существует ли простой способ, чтобы, если статус на листе 1 изменится на «Приостановлено» или «Версия возвращена», он удалит строку из листа 2? т.е., поскольку этот статус может измениться между редактированием и возвращенной версией, а затем вернуться к редактированию, строки копируются, а затем удаляются с листа 2?
Если у вас нет времени/энергии, то полностью получите это... более чем счастлив, чтобы PayPal выпил вам "напиток" за помощь...
Конечно, без проблем. Я немного изменил код и добавил условие, чтобы проверить, должна ли строка быть удалена из Sheet2 (пожалуйста, проверьте ссылку на пример из моего предыдущего комментария). Кроме того, просто для того, чтобы сфокусировать вопрос, я отправил вам запрос на подключение в LinkedIn, чтобы мы продолжили обсуждение расширений/модификаций там.
Вау, большое спасибо, что нашли время, чтобы помочь ... очень ценю. При попытке запустить первую часть (или 2-ю версию) я получаю это сообщение об ошибке.... Я попытался найти его в Google, чтобы понять это, но, нет, вне меня TypeError: Cannot read property 'range' of undefined (строка 5, файл "editon")