Home > Enterprise >  Finding the index of a placeholder text element in a google doc table using app script
Finding the index of a placeholder text element in a google doc table using app script

Time:04-27

As the title suggests I am trying to find the index of a placeholder text element in a google doc table so that I can replace it with text stored in a different doc.

I can get the pre-formatted text to be added to the document - not the place in the table required - using other examples I have found on stackoverflow.

However I am unclear as how to find the index of the placeholder element within one of many tables in the template document.

I need the index of the placeholder text to be able to use the insertParagraph function.

To add slightly more detail: I am able to find the placeholder text and insert an image using the below code.

function replaceTextToImage(body, searchText, image, width) {
var next = body.findText(searchText);
if (!next) return;
var r = next.getElement();
r.asText().setText("");
var img = r.getParent().asParagraph().insertInlineImage(0, image);
if (width && typeof width == "number") {
  var w = img.getWidth();
  var h = img.getHeight();
  img.setWidth(width);
  img.setHeight(width * h / w);
}
return next;

};

However, I need to preserve the formatting of the doc I want to import. So I open the document with the formatted text and then loop through the different element types with a conditional to insert the text/image if the element type is matched. This is why I need the index of the placeholder text. See for function below:

 function replaceTextWithDoc(body, searchText, id) {
  let doc = DocumentApp.openById(id)

  var numElements = body.getNumChildren();
  var index = numElements;

  for (var i = 0; i < numElements; i  ) {
    var child = body.getChild(i);
    if (child.asText().getText() == searchText){
      index = i;
      body.removeChild(child);
      break;
    }
  }
  var totalElements = doc.getNumChildren();
  for( var j = 0; j < totalElements;   j ) {
    var element = doc.getChild(j).copy();
    var type = element.getType();
    if( type == DocumentApp.ElementType.PARAGRAPH )
      body.insertParagraph(index, element);
    else if( type == DocumentApp.ElementType.TABLE )
      body.insertTable(index, element);
    else if( type == DocumentApp.ElementType.LIST_ITEM )
      body.insertParagraph(index, element);
    else
      throw new Error("According to the doc this type couldn't appear in the body: " type);
    }
  } 

Here is an example of the placeholder text ( {iText} ) in a table: https://docs.google.com/document/d/1mZWpQqk4gYAF6UCRALrT8S99-01RYNfwni_kqDzOg7E/edit?usp=sharing

Here is an example of text and images that I need to replace the placeholder text with - maintaining all/any formatting. https://docs.google.com/document/d/1wuX0g5W2GL0YJ7admiv3TNEepb_zVwQleKwazCiAMBU/edit?usp=sharing

CodePudding user response:

Issue:

If I understand you correctly, you want to copy the contents of one document (made up of text and inline images) to certain table cells that contain a certain placeholder text.

Solution:

In that case, I'd suggest the following:

  • Iterate through all tables in the target document, using Body.getTables().
  • For each table, iterate through all its cells.
  • For each cell, check whether its text contains the placeholder.
  • If the placeholder is included, clear the current cell content via TableCell.clear().
  • Iterate through all source document elements (see for example, this answer).
  • For each element, check its type (Element.getType()).
  • If the element is a paragraph, append the paragraph to the cell via TableCell.appendParagraph.
  • If the element is an image, append it via TableCell.appendImage.

Code sample:

const PLACEHOLDER = "{iText}";

function myFunction() {
  const doc = DocumentApp.openById(TARGET_ID);
  const sourceDoc = DocumentApp.openById(SOURCE_ID);
  const body = doc.getBody();
  const tables = body.getTables();
  tables.forEach(table => {
    const numRows = table.getNumRows();
    for (let i = 0; i < numRows; i  ) {
      const row = table.getRow(i);
      const numCells = row.getNumCells();
      for (let j = 0; j < numCells; j  ) {
        const cell = row.getCell(j);
        const cellText = cell.editAsText();
        const text = cellText.getText();
        if (text.includes(PLACEHOLDER)) {
          cell.clear();
          appendSourceContent(sourceDoc, cell);
        }
      }
    }
  });
}

function appendSourceContent(doc, cell) {
  const numChildren = doc.getNumChildren();
  for (let j = 0; j < numChildren; j  ) {
    const element = doc.getChild(j).copy();
    const type = element.getType();
    if (type == DocumentApp.ElementType.PARAGRAPH) {
      cell.appendParagraph(element);
    } else if (type == DocumentApp.ElementType.INLINE_IMAGE) {
      cell.appendImage(element);
    }
  }
}

Note:

  • Add additional else if blocks if the source content can have different ElementTypes than paragraphs and inline images.
  • I assumed that you want to preserve none of the current content in the table cell.
  • Related