Скрипт Google Apps: манипулирование данными на листах, удаление строк, если некоторые ячейки пусты, при ведении определенных столбцов - PullRequest
0 голосов
/ 16 апреля 2019

Этот вопрос является продолжением следующего: Скрипт Google Apps: манипуляции данными на листах и ​​удаление строк, если некоторые ячейки пустые

У меня есть лист «Формы ответов», где пользователи могут заполнять один и тот же вопрос до 5 раз. Следующий код организует эти строки строка за строкой на листе «Вставить значения». В дополнение к этому я попытался отсортировать столбцы по столбцу Timestamp в порядке возрастания (чтобы новые ответы из формы Google отображались вверху).

Первая проблема с этим заключается в том, что у меня есть дополнительные столбцы на моем листе вставленных значений (A, O, P, Q, R, S), которых нет в моем бланке форм. Когда новая форма переходит в начало, информация в этих столбцах не перемещается с правильной строкой, в которой они должны были находиться; они просто остаются там, где они есть.

Вторая проблема заключается в том, что если я попытаюсь добавить триггер On Form Submit, чтобы лист Paste Values ​​обновлялся каждый раз при отправке новой формы, строки будут накапливаться от начала до конца

Так, например, если у меня есть:
Row1
Стр2
Row3

И тогда отправляется новая форма, она становится:
Row1
Стр2
Row3
Row1
Стр2
Row3
Row4

Это приводит к дублированию строк, которые мне не нужны.

Моя конечная цель - достичь следующего:

1) каждый раз, когда кто-то отправляет новую форму, ответы приходят наверх; все отсортировано в порядке возрастания (по столбцу меток времени) в «ответах формы» и «вставленных значениях»

2) Добавить триггер при редактировании, чтобы каждый раз, когда пользователь отправлял форму, в «Вставить значения» добавлялись только новые строки, а не все строки, дублирующиеся снова и снова

3) Столбцы: A, O, P, Q, R, S и T - это столбцы, которые я хочу свободно редактировать в «Вставить значения», то есть каждый раз, когда в «Вставить» добавляется новая строка Значения ', соответствующая информация в этих столбцах перемещается вместе с этой строкой, и на нее не влияет триггер On Edit.

Вот пример листа Google: https://docs.google.com/spreadsheets/d/1QUzPxxPB6CDL7Y5Dh92w6nsEM0QFUAaGG9LomjnGgLM/edit?usp=sharing

Лист ответов формы - это данные, полученные формой Google. Вставьте значения «это цель» и я хочу, чтобы она стала

код для работы со строками:

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var src = ss.getSheetByName("Form Responses");
  var dst = ss.getSheetByName("Paste Values");
  var values = src.getDataRange().getValues();
  var header = values.splice(0, 1)[0].splice(0, 13);
  var res = values.reduce(function(ar, e) {
    var h = e.splice(0, 3);
    h.unshift("");
    for (var i = 0; i < 5; i++) {
      var temp = e.splice(0, 10);
      if (temp.filter(String).length == 0) continue;
      if (temp.length < 10) temp.splice(temp.length, 10 - temp.length, "");
      ar.push(h.concat(temp));
    }
    return ar;
  }, []);
  if (dst.getRange("A1").getValue() != "Status") res.unshift(["Status"].concat(header));
  dst.getRange(dst.getLastRow() + 1, 1, res.length, res[0].length).setValues(res);
}

И код для сортировки каждой строки в порядке возрастания по столбцу Timestamp:

// Sort Timestamp column from newest to oldest: 

function Sort_Timestamp(event){
  var spreadsheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses");
  var editedCell = spreadsheet1.getActiveRange().getColumnIndex();

  var columnToSortBy = 1;
  var tableRange = "A:AZ";

  if(editedCell == columnToSortBy){   
    var range = spreadsheet1.getRange(tableRange);
    range.sort( { column : columnToSortBy, ascending: false } );
  }
}

Обновлена ​​попытка достичь Манипуляции строк в Paste Values ​​(и вернуть каждую строку (разделяя их) из каждой строки ответов формы):

function so55716140_01(event) {
  // setup this function as an installable trigger OnFormSubmit

  // set up spreadsheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourcename = "Form Responses";
  var targetname = "Paste Values";
  var sourcesheet = ss.getSheetByName(sourcename);
  var targetsheet = ss.getSheetByName(targetname);

  // get the response data - assumes 10 questions plus timestamp
  var sourcerow = event.range.getRow();
  // Logger.log("DEBUG: Response row = "+sourcerow); //DEBUG
  var sourcerange = sourcesheet.getRange(sourcerow, 1, 1, 12);  // getRange(source row, column #, number of rows, number of columns); so 13  goes to column N in form resonses "do you want to submit another form" 
  var sourcerange2 = sourcesheet.getRange(sourcerow, 13, 1, 10);  //want to start at column 13 (col M)
  var sourcerange3 = sourcesheet.getRange(sourcerow, 23, 1, 10);  // third round column W
  var sourcerange4 = sourcesheet.getRange(sourcerow, 33, 1, 10);  // fourth round
  var sourcerange5 = sourcesheet.getRange(sourcerow, 43, 1, 9);  // fifth round

  //Logger.log("DEBUG: Source range = "+sourcerange.getA1Notation()); //DEBUG
  var sourcedata = sourcerange.getValues();
  var sourcedata2 = sourcerange2.getValues();
  var sourcedata3 = sourcerange3.getValues();
  var sourcedata4 = sourcerange4.getValues();
  var sourcedata5 = sourcerange5.getValues();

  // setup the target
  var Bvals = targetsheet.getRange("B1:B").getValues();
  var Blast = Bvals.filter(String).length;
  //Logger.log("DEBUG: Blast = "+Blast); //DEBUG
  var targetrange = targetsheet.getRange(Blast + 1, 2, 1, 12);  //you're starting at the next row. so if there is data in column B3 row 2, you'll start at column B3 row 3
    // starting at column 2 in Paste Values (timestamp), only on that one row, and paste in the next 12 values (started at column 2)
  var targetrange2 = targetsheet.getRange(Blast + 2, 4, 1, 10);  //trying blast + 2, and you're only pasting 10 values
  //Logger.log("DEBUG: Target range = "+targetrange.getA1Notation()); //DEBUG
  var targetrange3 = targetsheet.getRange(Blast + 3, 4, 1, 10);
  var targetrange4 = targetsheet.getRange(Blast + 4, 4, 1, 10);
  var targetrange5 = targetsheet.getRange(Blast + 5, 4, 1, 9);

  // paste the response to the target
  targetrange.setValues(sourcedata);
  targetrange2.setValues(sourcedata2);
  targetrange3.setValues(sourcedata3);
  targetrange4.setValues(sourcedata4);
  targetrange5.setValues(sourcedata5);
 }

1 Ответ

1 голос
/ 19 апреля 2019

Код Танаике - произведение искусства, но я думаю, что он основан на предположении, что вы запустите сценарий только один раз.

Вы сказали, что пользователи будут заполнять форму Google. Затем вы управляете этим, чтобы строки с одинаковыми столбцами были перенесены в один столбец. Но по иронии судьбы вы затем разбираете это, чтобы получить результаты «Вставить значения».

Я предлагаю гораздо менее сложный процесс:

  • создайте и установите заголовок для "Вставить значения" до получения ответов на любые формы.
  • написать скрипт, который устанавливается вручную как OnFormSubmit' trigger. Используйте данные объекта, возвращаемые триггером, чтобы скопировать соответствующие данные в последнюю строку (плюс 1) «Вставить значения». Возможно, вы захотите изменить форму так, чтобы имя Отправителя было выбрано из выпадающего списка, чтобы обеспечить правильное написание.
  • сортировать «Вставить значения» постепенно; добавьте код к триггеру FormSubmit.

Это позволяет вам записывать свои заметки и другие комментарии в Paste Values, и они будут выровнены с соответствующей строкой после сортировки.

КОД

function so55716140_01(event) {
  // setup this function as an installable trigger OnFormSubmit

  // set up spreadsheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourcename = "Form Responses 2";
  var targetname = "Paste Values";
  var sourcesheet = ss.getSheetByName(sourcename);
  var targetsheet = ss.getSheetByName(targetname);

  // get the response data - assumes 10 questions plus timestamp
  var sourcerow = event.range.getRow();
  // Logger.log("DEBUG: Response row = "+sourcerow); //DEBUG
  var sourcerange = sourcesheet.getRange(sourcerow, 1, 1, 11);
  //Logger.log("DEBUG: Source range = "+sourcerange.getA1Notation()); //DEBUG
  var sourcedata = sourcerange.getValues();

  // setup the target
  var Bvals = targetsheet.getRange("B1:B").getValues();
  var Blast = Bvals.filter(String).length;
  //Logger.log("DEBUG: Blast = "+Blast); //DEBUG
  var targetrange = targetsheet.getRange(Blast + 1, 2, 1, 11);
  //Logger.log("DEBUG: Target range = "+targetrange.getA1Notation()); //DEBUG

  // paste the response to the target
  targetrange.setValues(sourcedata);

 // OP to add sort code according to preference
}

Код для формы, имеющей 5 разделов

function ejb_op3(event) {

  // setup this function as an installable trigger OnFormSubmit

  // set up spreadsheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourcename = "Form Responses 4";
  var targetname = "Paste Values";
  var sourcesheet = ss.getSheetByName(sourcename);
  var targetsheet = ss.getSheetByName(targetname);

  // get the response row and range
  var sourcerow = event.range.getRow();
  //Logger.log("DEBUG: Response row = "+sourcerow); //DEBUG

  // range is from Column A to Column AZ: 52 columns; 3=common; 4x10 (40) = printer "section" questions PLUS "do you want to submit another form"; the final (5th) 1x9 printer "section" questions; 3+40+9=52
  var sourcerange = sourcesheet.getRange(sourcerow, 1, 1, 52);
  //Logger.log("DEBUG: Source range = "+sourcerange.getA1Notation()); //DEBUG

  // get the response data
  var sourcedata = sourcerange.getValues();

  // find the number of rows already populated on the target
  var Bvals = targetsheet.getRange("B1:B").getValues();
  var Blast = Bvals.filter(String).length;
  //Logger.log("DEBUG: Blast = "+Blast); //DEBUG

  // establish some variables
  var datastart = 3; // the first 3 columns are common data
  var dataqty = 10; // the first 4 responses have 10 columns of response data
  var printcount = 0; // status counter
  var responsecount = 0; // column status counter
  var responsedata = []; // array to compile responses

  // process the first section
  if (printcount == 0) {
    responsedata = [];

    // get the timestamp, submitter name and email
    responsedata.push(sourcedata[0][0]);
    responsedata.push(sourcedata[0][1]);
    responsedata.push(sourcedata[0][2]);

    //get the responses for the next 10 questions
    for (i = datastart; i < (datastart + dataqty); i++) {
      responsedata.push(sourcedata[0][i]);
    }

    // define the target range
    // the last line (Blast)plus one line plus the print count; column B; 1 row; 13 columns
    var targetrange = targetsheet.getRange(Blast + 1 + printcount, 2, 1, 13);
    // paste the values to the target
    targetrange.setValues([responsedata]);

    // update variables
    responsecount = i; // copy the value of i
    printcount++; // update status counter
    responsedata = []; // clear the array ready for the next section
  }
  // end opening response

  // build routine for 2nd to 4th sections
  for (z = 2; z < 5; z++) {

    //Make sure not to double count the first section
    if (printcount > 0 && printcount < 5) {

      // test if the next section exists
      if (sourcedata[0][i - 1] == "Yes") {
        // Yes for next section
        //Logger.log("DEBUG: value = "+sourcedata[0][i-1]);  //DEBUG

        // get the timestamp, submitter name and email
        responsedata.push(sourcedata[0][0]);
        responsedata.push(sourcedata[0][1]);
        responsedata.push(sourcedata[0][2]);

        //get the responses for the next 10 questions
        for (i = responsecount; i < (responsecount + dataqty); i++) {
          responsedata.push(sourcedata[0][i]);
          //Logger.log("DEBUG: data: "+sourcedata[0][i]);//DEBUG
        }

        // define the target range
        // the last line (Blast) plus one line plus the print count; column B; 1 row; 13 columns
        targetrange = targetsheet.getRange(Blast + 1 + printcount, 2, 1, 13);
        // paste the values to the target
        targetrange.setValues([responsedata]);

        // update variables
        responsecount = i;
        printcount++;
        responsedata = [];
      } else {
        // NO for next section
      }
      // end routine if the next section exists
    } // end routine for the next section
  } // end routine for sections 2, 3 and 4

  // checking for 5th response
  if (printcount == 4) {

    // test if response exists
    if (sourcedata[0][i - 1] == "Yes") {
      // Yes for next section
      //Logger.log("DEBUG: value = "+sourcedata[0][i-1]);  //DEBUG

      // get the timestamp, submitter name and email
      responsedata.push(sourcedata[0][0]);
      responsedata.push(sourcedata[0][1]);
      responsedata.push(sourcedata[0][2]);

      //get the responses for the next 9 (nine) questions
      for (i = responsecount; i < (responsecount + dataqty - 1); i++) {
        responsedata.push(sourcedata[0][i]);
        //Logger.log("DEBUG: data: "+sourcedata[0][i]);//DEBUG
      }

      // define the target range
      // the last line (Blast) plus one line plus the print count; column B; 1 row; 12 columns only
      targetrange = targetsheet.getRange(Blast + 1 + printcount, 2, 1, 12);
      // paste the values to the target
      targetrange.setValues([responsedata]);
    } else {
      // NO for next section
    }
  }
  // end routine for the 5th section


}
...