0

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

Doddy
  • 27
  • 5
  • Hi, I posted an answer to this, I hope it is useful to you. Since you didn't provide much information about your situation, I'm not sure whether this answer tackles your issue. In that case, consider providing more information to clarify your goal (e.g. sample doc). – Iamblichus Apr 26 '22 at 10:38
  • Hi @lamblichus - thanks for your comment. Perhaps I should have provided more information. Using replaceText() works when replacing the placeholder for a string. However, I need to replace the placeholder text with text and images stored in another document. I need to maintain the formatting of this document. To achieve this, I am opening the doc where the formatted text is stored, looping through the different element types, copying them and then (trying) to replace the placeholder text with them. This is why I need the index of the placeholder. – Doddy Apr 26 '22 at 11:19
  • Consider providing a copy of the document you're working on, this is a considerably more complex issue than what could be seen in your original question. – Iamblichus Apr 26 '22 at 11:51
  • @lamblichus I have updated the original question with example docs. – Doddy Apr 26 '22 at 12:09
  • I'm struggling to understand why I can use the above replaceTextToImage() function to insert an image at the correct location but when I try to modify the function to insert text it doesnt work. – Doddy Apr 26 '22 at 12:25

1 Answers1

1

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.
Iamblichus
  • 18,540
  • 2
  • 11
  • 27
  • Yep that's it. Thank you very much for your help. Appreciate you taking the time to find a resolution to this for me. – Doddy Apr 27 '22 at 09:35