0

Formatting and image not working

I am utilizing a script I found online to create name cards for our guests to wear on a lanyard. We would be printing these on perforated 3x5 cards. This pulls data from a sheet Link to populate into a document template Link.

I am able to get text fields to work with the exception of being centered, but the inserted image will not copy to the copied tables.

The script is as follows:

const g = {
  docId: '14Pa2L0gudkiDbDBQFXztY2Gd5J8u3hlmARaH0F_LIPE',
};
function init_() {
  g.doc = DocumentApp.openById(g.docId);
  g.body = g.doc.getBody();
  g.ss = SpreadsheetApp.getActive();
}
function CreateGuestID() {
  init_();
  const sh = g.ss.getSheetByName('guests');
  [g.guestsHeaders, ...g.guestsData] = sh.getDataRange().getValues();
  const templateTable = g.body.getTables()[0];
  const templateCell = templateTable.getCell(0, 0).copy();
  const numLines = templateCell.getNumChildren();
  const templateTexts = [];
  const templateAttributes = [];
  for (let i = 0; i < numLines; i++) {
  const child = templateCell.getChild(i);
  templateTexts.push(child.getText());
  const sourceAttributes = child.getAttributes();
  const atts = {};
  Object.entries(sourceAttributes).forEach(([k, v]) => {
    if (!(v instanceof Object)) {
      atts[k] = v;
    }
  });
  templateAttributes.push(atts);
}
const bodyChildren = g.body.getNumChildren();
for (let i = bodyChildren - 2; i > 1; i--) {
  g.body.removeChild(g.body.getChild(i)); 
}
const numRows = templateTable.getNumRows();
const numCols = templateTable.getRow(0).getNumCells();
let iCol = Infinity;
let iRow = Infinity;
let table;
g.guestsData.forEach((recipient) => {
  if (iCol >= numCols) {
   iCol = 0;
   iRow++;
  }
  if (iRow >= numRows) {
    iRow = 0;
    table = g.body.appendTable(templateTable.copy());
    table.setBorderWidth(0);
    table.getCell(0, 0).clear();
  }
  const newCell = table.getCell(iRow, iCol);
  newCell.clear();
  templateTexts.forEach((templateText, i) => {
    const newLine = merge_(templateText, recipient);
    const par = newCell.insertParagraph(i, newLine);
    par.editAsText().setAttributes(templateAttributes[i]);
    par.setForegroundColor(templateAttributes[i].FOREGROUND_COLOR);
  });
  iCol++;
});
g.doc.saveAndClose();
}
function merge_(text, recipient) {
  g.guestsHeaders.forEach((header, i) => {
    text = text.replace(`%${header}%`, recipient[i]);
});
   return text;  
}

I would be grateful for any assistance.

  • I think [this answer](https://stackoverflow.com/a/53877859/13771937) might help you get going. Basically the inline image is not getting copied because it's actually not a first level child of the cell. I think you might be thinking that the inline Image is a direct child of the cell as opposed to a child of the paragraph element (which is a direct child of the cell). This is most likely also why the styling isn't copying over. – Miguel Rivera Rios Jul 25 '23 at 22:07
  • I have to apologize for my poor English skill. Unfortunately, I cannot understand your question. In order to correctly understand your question, can you provide the sample input and output situations you expect? First, I would like to correctly understand your question. – Tanaike Jul 26 '23 at 00:52
  • @Tanaike In my document template link [Link](https://docs.google.com/document/d/14Pa2L0gudkiDbDBQFXztY2Gd5J8u3hlmARaH0F_LIPE/edit?usp=sharing) there is a template cell which is the first table. Following that there are outputs I cam currently receiving. All I am looking for is the outputs to contain the image like the template and have text centered. I hope this is clearer. – user22283843 Jul 26 '23 at 15:09

1 Answers1

0

For those interested I was able to get this working with this code. It will include the inline image and text as well as open the doc for printing.

const g = {
  docId: 'Insert_Template_ID',
};

function init_() {
  g.doc = DocumentApp.openById(g.docId);
  g.body = g.doc.getBody();
  g.ss = SpreadsheetApp.getActive();
}

function CreateGuestID() {
  init_();
  const sh = g.ss.getSheetByName('guests');
  [g.guestsHeaders, ...g.guestsData] = sh.getDataRange().getValues();
  const templateTable = g.body.getTables()[0];
  const templateCell = templateTable.getCell(0, 0).copy();
  const numLines = templateCell.getNumChildren();
  const templateTexts = [];
  const templateAttributes = [];

  let imageBlob = null;
  for (let i = 0; i < numLines; i++) {
    const childElement = templateCell.getChild(i);
    if (childElement.getType() === DocumentApp.ElementType.PARAGRAPH) {
      const para = childElement.asParagraph();
      for (let j = 0; j < para.getNumChildren(); j++) {
        const paraChild = para.getChild(j);
        if (paraChild.getType() === DocumentApp.ElementType.INLINE_IMAGE) {
          imageBlob = paraChild.asInlineImage().getBlob();
        }
      }
      templateTexts.push(para.getText());
    }

    const sourceAttributes = childElement.getAttributes();
    const atts = {};
    Object.entries(sourceAttributes).forEach(([k, v]) => {
      if (!(v instanceof Object)) {
        atts[k] = v;
      }
    });
    templateAttributes.push(atts);
  }

  const bodyChildren = g.body.getNumChildren();
  for (let i = bodyChildren - 2; i > 1; i--) {
    g.body.removeChild(g.body.getChild(i));
  }

  const numRows = templateTable.getNumRows();
  const numCols = templateTable.getRow(0).getNumCells();
  let iCol = Infinity;
  let iRow = Infinity;
  let table;

  g.guestsData.forEach((recipient) => {
    if (iCol >= numCols) {
      iCol = 0;
      iRow++;
    }
    if (iRow >= numRows) {
      iRow = 0;
      table = g.body.appendTable(templateTable.copy());
      table.setBorderWidth(0);
      table.getCell(0, 0).clear();
    }
    const newCell = table.getCell(iRow, iCol);
    newCell.clear();

    if (imageBlob) {
      const paragraphInCell = newCell.getChild(0).asParagraph();
      paragraphInCell.insertInlineImage(0, imageBlob);
    }

    templateTexts.forEach((templateText, i) => {
      const newLine = merge_(templateText, recipient);
      const par = newCell.appendParagraph(newLine);
      par.editAsText().setAttributes(templateAttributes[i]);
      par.setForegroundColor(templateAttributes[i].FOREGROUND_COLOR);
      par.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
    });
    iCol++;
  });

  openDocumentInNewTab(g.doc.getUrl());

  g.doc.saveAndClose();
}

function merge_(text, recipient) {
  g.guestsHeaders.forEach((header, i) => {
    text = text.replace(`%${header}%`, recipient[i]);
  });
  return text;
}

function openDocumentInNewTab(url) {
  const html = `<script>window.open('${url}', '_blank');google.script.host.close();</script>`;
  const userInterface = HtmlService.createHtmlOutput(html)
      .setWidth(10)
      .setHeight(10);
  SpreadsheetApp.getUi().showModalDialog(userInterface, 'Opening Document...');
}
  • Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. **Would you kindly [edit] your answer to include additional details for the benefit of the community?** – Jeremy Caney Jul 31 '23 at 00:54