Retrieve values from Spreadsheet custom columns and put to template Document

余生颓废 提交于 2020-05-17 06:22:26

问题


This script, in my Spreadsheet, retrieve all values of columns of "A" and "B" that are the same for all rows and retrieve all values of columns of "C","D" and "E" that are variables for all the rows.
The script creates one Google Document by replacing the placeholder by the values from Spreadsheet.
The placeholder is enclosed by %.

How to set, in the script, the columns if they change and so to set custom columns?

function myFunction() {
  var templateGoogleDocumentID = "###";  // Please set the template Google Document ID.

  // 1. Retrieve values from Spreadsheet.
  var activeSheet = SpreadsheetApp.getActiveSheet();
  var values = activeSheet.getDataRange().getValues();

  // 2. Create an object for putting to Google Document.
  var object = {headers: {}, table: {}};
  var headerRow = values.shift();
  object.headers[headerRow[0]] = values[0][0];
  object.headers[headerRow[1]] = Utilities.formatDate(values[0][1], Session.getScriptTimeZone(), "yyyy/MM/dd");
  object.table = values.map(r => r.splice(2, 5));

  // 3. Copy a template Google Document.
  var copiedTemplateDoc = DriveApp.getFileById(templateGoogleDocumentID).makeCopy();
  var docId = copiedTemplateDoc.getId();

  // 4. Put the header values to the copied Document using the object.
  var doc = DocumentApp.openById(docId);
  var body = doc.getBody();
  Object.keys(object.headers).forEach(h => body.replaceText(`%${h.toLowerCase()}%`, object.headers[h]));

  // 5. Put the table values using the object.
  // If the table rows of Google Document are less than that of Spreadsheet, the rows are added.
  var table = body.getTables()[0];
  var r = object.table.length - table.getNumRows();
  if (r > 0) {
    for (var i = 0; i < r; i++) {
      var tr = table.appendTableRow();
      for (var j = 0; j < 3; j++) {
        tr.appendTableCell();
      }
    }
  }
  object.table.forEach((row, i) => (row.forEach((col, j) => (table.getCell(i, j).setText(col)))));
  doc.saveAndClose();

  // If you want to export the Google Document as PDF file, please use the following script.
  // var newFile = DriveApp.createFile(doc.getBlob());
}

回答1:


You want to do the following:

  • Copy certain rows to a Document template.
  • Copy only some of the columns (you will specify their indexes manually).
  • Some columns are "fixed data" and will replace some placeholders on the top of the document.
  • Some columns are "variable data" and a table will be created with such data.
  • Some "variable data" are dates that need to be formatted.
  • The data is copied to a copy of the Document template, to a specified folder.

Depending on how you want to select the rows to copy to the template, there are two methods you can follow:

Method #1: Copying selected rows:

This method will create the document faster, but you have to manually select all rows you want to copy to the template, one by one (excluding the headers row).

function exportSelectedRows() {
  var templateGoogleDocumentID = "#########";  // Please set the template Google Document ID.
  var destinationFolderID = "#########"; // Please set the destination folder ID
  var activeSheet = SpreadsheetApp.getActiveSheet();
  var headers = activeSheet.getRange(1, 1, 1, activeSheet.getLastRow()).getValues()[0]; // Get header values
  var values = activeSheet.getActiveRangeList().getRanges().map(range => range.getValues()).flat(); // Get the values of the selected rows
  values.unshift(headers);
  var fixedColumns = [1, 3, 4, 9]; // Fixed column indexes: B, D, E, J  
  var variableColumns = [10, 11, 12, 13, 21, 33]; // Variable column indexes: K,L,M,N,V,AH
  var fixedValues = removeUnwantedColumns(fixedColumns, values).slice(0, 2); // Retrieve fixed values (only header and one row is needed)
  var varValues = removeUnwantedColumns(variableColumns, values).map(row => row.map(value => { // Retrieve variable values (dates are formatted)
    if (Object.prototype.toString.call(value) === "[object Date]") {
      return Utilities.formatDate(new Date(value), Session.getScriptTimeZone(), "yyyy/MM/dd");
    } else return value;
  }));  
  // Create template copy:
  var folder = DriveApp.getFolderById(destinationFolderID); // Get folder with specified destinationFolderID
  var copiedTemplateDoc = DriveApp.getFileById(templateGoogleDocumentID).makeCopy(folder); // Copy template to destination folder
  var docId = copiedTemplateDoc.getId();
  var doc = DocumentApp.openById(docId);
  var body = doc.getBody();
  for (var i = 0; i < fixedValues[0].length; i++) {
    body.replaceText(`%${fixedValues[0][i]}%`, fixedValues[1][i]); // Replace fixed data with placeholders
  }
  body.appendTable(varValues); // Insert new table to document
  var table = body.getTables()[0];
  table.removeFromParent(); // Remove old table
}

function removeUnwantedColumns(columnsToKeep, values) {
  return values.map(row => row.filter((col, i) => columnsToKeep.includes(i)));
}

Method #2: Copying filtered rows:

In this method, the execution will take more time, specially if the sheet has many rows, but there is no need no manually select the rows, the filter handles this.

The script is almost like the one from method #1, but you would have to replace this line:

var values = activeSheet.getActiveRangeList().getRanges().map(range => range.getValues()).flat(); // Get the values of the selected rows

With this one:

var values = activeSheet.getDataRange().getValues().filter((row, i) => !activeSheet.isRowHiddenByFilter(i + 1)); // Remove filtered data

Notes:

  • You should manually define the indexes of (1) fixed columns (fixedColumns), (2) variable columns (variableColumns) and (3) variable columns with date to be formatted (formatDateColumns).
  • You should manually specify the templateGoogleDocumentID and the destinationFolderID in your code (check inline comments).
  • The sheet headers should match the placeholder values in the document for this to work, including case (in the copy you shared, for example, the placeholder was written like Codice FIscale, instead of Codice Fiscale).
  • The table columns are not getting copied according to any placeholder, but according to their relative position in the sheet. Headers are being copied too.
  • Instead of checking whether the table dimensions match the data dimensions, I think it's better to create a new table with the right dimensions and remove the old one.


来源:https://stackoverflow.com/questions/61025816/retrieve-values-from-spreadsheet-custom-columns-and-put-to-template-document

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!