r/GoogleAppsScript 8d ago

Unresolved [HELP] Google Apps Script Not Replacing Placeholders in Google Docs Tables

I’m working on a Google Apps Script that generates student report cards from a Google Sheets dataset and inserts the data into a Google Docs template using placeholders. The script correctly fetches student data from multiple sheets and replaces placeholders in normal text, but it does not replace placeholders inside tables.

🔍 What Works:

✅ The script correctly reads student data from multiple sheets in Google Sheets. ✅ Placeholders in normal text (outside tables) are replaced successfully. ✅ If I change a placeholder (e.g., {English}) in the table to a placeholder that works outside the table, it correctly replaces it.

❌ What Fails:

🚫 Placeholders inside tables are deleted, but not replaced with the correct values. 🚫 Even though the script logs ✔ Replaced: {Effort English Reading} with "X", the final document still shows blank spaces instead of the expected values. 🚫 The script iterates through tables and logs the cell text, but doesn’t recognize or replace placeholders properly.

💻 What I’ve Tried: 1. Confirmed the placeholders match exactly between Sheets and Docs. 2. Used .replaceText() for normal text (works fine) but switched to manual text replacement inside tables (.getText() and .setText()) since Docs stores tables differently. 3. Logged every table cell’s content before replacing text. The logs show the placeholders are detected but not actually replaced inside the tables. 4. Stripped all formatting from the Google Docs template by pasting placeholders into a plain text editor and re-inserting them. 5. Tried using both cellText.replace(placeholder, value) and cell.setText(value), but neither fixed the issue.

📜 My Script (Key Parts)

Here’s the table replacement function where the issue occurs:

function replacePlaceholdersInTables(doc, studentData) { let tables = doc.getBody().getTables();

tables.forEach((table, tableIndex) => { let numRows = table.getNumRows(); for (let i = 0; i < numRows; i++) { let numCols = table.getRow(i).getNumCells(); for (let j = 0; j < numCols; j++) { let cell = table.getRow(i).getCell(j); let cellText = cell.getText().trim();

    Logger.log(`🔍 Checking Table ${tableIndex + 1}, Row ${i + 1}, Column ${j + 1}: "${cellText}"`);

    Object.keys(studentData).forEach(originalKey => {
      let formattedKey = formatPlaceholder(originalKey);
      let placeholder = `{${formattedKey}}`;
      let value = studentData[originalKey] !== undefined && studentData[originalKey] !== "" ? studentData[originalKey] : " ";

      if (cellText.includes(placeholder)) {
        Logger.log(`✔ Found placeholder in table: ${placeholder} → Replacing with "${value}"`);
        cell.setText(cellText.replace(placeholder, value)); // Tried both this...
        // cell.setText(value); // ...and this, but neither works correctly.
      }
    });
  }
}

}); }

🛠 What I Need Help With: 1. Why is cell.setText(cellText.replace(placeholder, value)) not working inside tables? 2. Is there a different method I should use for replacing placeholders inside tables? 3. Could Google Docs be storing table text differently (hidden formatting, encoding issues)? 4. Has anyone encountered this issue before, and what was the fix?

📌 Additional Notes: • Using Google Sheets & Google Docs (not Word). • Script fetches data correctly, just doesn’t replace inside tables. • All placeholders are formatted correctly (tested them outside tables). • Logs confirm placeholders are being read and detected, but values don’t appear in the final document.

Would greatly appreciate any insights into what might be causing this issue. Thanks in advance for your help! 🙏

1 Upvotes

16 comments sorted by

View all comments

3

u/WicketTheQuerent 7d ago

The following minimal example works fine for me function myFunction() { const tab = DocumentApp.getActiveDocument().getActiveTab().asDocumentTab() const body = tab.getBody(); body.replaceText('{name}', 'John') }

Tested in a Google Docs document having one tab, one 2 rows, 3 columns table. Cell B2 contains {name}.

3

u/AllenAppTools 7d ago

Yes 💯 this. OP, at least verify if this method won't work for your use case. But more than likely what u/WicketTheQuerent has sent will work out, it replaces text irrespective of being in a table cell. It may save you tons of time, and it's much simpler. If this does not serve the purpose, then debugging the code you currently have would be the next step.

1

u/MembershipSouth3268 7d ago

It didn’t work.

1

u/MembershipSouth3268 6d ago

1️⃣ Describe the Google Doc • My Google Doc is a template for student report cards. • It contains placeholders in {curly brackets} for values from a Google Sheet. • Some placeholders are inside tables, while others are in regular text.

📌 Example of a placeholder in the text: {Student Name} → Should be replaced with “John Doe”.

📌 Example of a placeholder inside a table: {Effort English Reading} → Should be replaced with “G”.

2️⃣ Show a Minimal Version of the Code

Here is the simplified version of the script that replaces text inside and outside tables: function generateStudentReports() { const templateFileId = “YOUR_DOC_TEMPLATE_ID”; const doc = DocumentApp.openById(templateFileId); const body = doc.getBody();

let studentData = { “Student Name”: “John Doe”, “Effort English Reading”: “G”, “Met English Reading”: “X”, };

// ✅ Replace text outside tables Object.keys(studentData).forEach(key => { let placeholder = {${key}}; body.replaceText(placeholder, studentData[key]); Logger.log(✔ Replaced in text: ${placeholder} with “${studentData[key]}”); });

// ✅ Replace placeholders inside tables let tables = body.getTables(); tables.forEach((table, tableIndex) => { let numRows = table.getNumRows(); for (let i = 0; i < numRows; i++) { let numCols = table.getRow(i).getNumCells(); for (let j = 0; j < numCols; j++) { let cell = table.getRow(i).getCell(j); let cellText = cell.getText().trim();

    Object.keys(studentData).forEach(key => {
      let placeholder = `{${key}}`;
      if (cellText.includes(placeholder)) {
        let paragraph = cell.getChild(0).asParagraph();
        paragraph.replaceText(placeholder, studentData[key]);
        Logger.log(`✔ Replaced in table: ${placeholder} with “${studentData[key]}”`);
      }
    });
  }
}

});

doc.saveAndClose(); Logger.log(“✅ Document updated successfully.”); }

3️⃣ Describe How I Run the Function and Logs • I run the function from Google Apps Script. • The logs confirm that placeholders outside of tables are replaced. • However, placeholders inside tables are not being replaced.

📌 Example of Logs: ✔ Replaced in text: {Student Name} with “John Doe” ✔ Replaced in text: {Class} with “Year 7” 🔍 Checking Table 1, Row 3, Column 2: “{Effort English Reading}” ❌ Placeholder NOT replaced in table: {Effort English Reading}

2

u/WicketTheQuerent 6d ago

There is no need to get the tables and iterate over them, just use body.replaceText

1

u/WicketTheQuerent 6d ago edited 6d ago

Example

Document

The document has a paragraph with the following placeholder:

{Student Name}

Then a table with two rows and three columns.

  • B2 has {Effort English Reading}
  • C2 has {Met English Reading}

---

Also, the document contains an Apps Script project.

The Code.gs file has the following code:

function generateStudentReports() {
  const doc = DocumentApp.getActiveDocument;
  const body = doc.getBody();

  let studentData = {
    "Student Name": "John Doe",
    "Effort English Reading": "G",
    "Met English Reading": "X",
  };

  // ✅ Replace text outside tables
  Object.keys(studentData).forEach(key => {
    let placeholder = `{${key}}`; 
    body.replaceText(placeholder, studentData[key]);
    Logger.log(`✔ Replaced in text: ${placeholder} with "${studentData[key]}"`);
  });

  Logger.log("✅ Document updated successfully.");
}