Как условно скопировать строку в листах google на вкладку в цикле, но не дублировать

Хорошо, полный новичок здесь ... Я искал и нашел различные сценарии «копировать строку на другой лист», но могу заставить работать только один. Вот моя версия ниже. Что я пытаюсь сделать, так это иметь передний лист, на котором отображаются строки из листа 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;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
178
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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);
    }    
  }
}

Вау, большое спасибо, что нашли время, чтобы помочь ... очень ценю. При попытке запустить первую часть (или 2-ю версию) я получаю это сообщение об ошибке.... Я попытался найти его в Google, чтобы понять это, но, нет, вне меня TypeError: Cannot read property 'range' of undefined (строка 5, файл "editon")

Ben Draycott-Jones 11.12.2020 08:09

Это потому, что вы, вероятно, пытаетесь запустить функцию из редактора, но, поскольку это триггер, он вызывается автоматически при каждом изменении листа. Как вы планируете выполнять эту функцию, вручную из редактора или позволить ей выполняться как автоматический триггер?

mshcruz 11.12.2020 08:15

Ааа..... это снова выдвинет на первый план мою нубность :) В идеале, автоматический триггер был бы замечательным Еще раз, спасибо, что развлекли мою неумелость, когда дело доходит до этого. Последнее кодирование, которое я делал в рамках своей инженерной степени, включало турбо-паскаль :)

Ben Draycott-Jones 11.12.2020 08:39

Не беспокойтесь :) Если вы хотите использовать его в качестве триггера, вам просто нужно включить его в свой Code.gs и сохранить. Всякий раз, когда лист редактируется, функция onEdit() будет вызываться автоматически. Вот лист, который я использовал для тестирования: docs.google.com/spreadsheets/d/…

mshcruz 11.12.2020 08:44

Понял, понял, как теперь работает триггер. Да, это работает блестяще. Но есть одна оплошность с моей стороны, которую я не продумал. Они отслеживают анимационные проекты, и в проекты будут внесены поправки. Это ДОБАВЛЯЕТ живые проекты, но не УДАЛЯЕТ неживые. Существует ли простой способ, чтобы, если статус на листе 1 изменится на «Приостановлено» или «Версия возвращена», он удалит строку из листа 2? т.е., поскольку этот статус может измениться между редактированием и возвращенной версией, а затем вернуться к редактированию, строки копируются, а затем удаляются с листа 2?

Ben Draycott-Jones 13.12.2020 02:19

Если у вас нет времени/энергии, то полностью получите это... более чем счастлив, чтобы PayPal выпил вам "напиток" за помощь...

Ben Draycott-Jones 13.12.2020 02:19

Конечно, без проблем. Я немного изменил код и добавил условие, чтобы проверить, должна ли строка быть удалена из Sheet2 (пожалуйста, проверьте ссылку на пример из моего предыдущего комментария). Кроме того, просто для того, чтобы сфокусировать вопрос, я отправил вам запрос на подключение в LinkedIn, чтобы мы продолжили обсуждение расширений/модификаций там.

mshcruz 14.12.2020 11:34

Другие вопросы по теме