# DocumentApp voor documentautomatisering [[TOC]] ## DocumentApp inleiding DocumentApp geeft je volledige controle over Google Docs vanuit Apps Script. Je kunt documenten aanmaken, inhoud toevoegen, tekst opmaken, tabellen beheren en sjablonen samenvoegen. Dat maakt het de geschikte service voor het automatiseren van rapportages, contracten en gepersonaliseerde brieven. ```javascript const doc = DocumentApp.getActiveDocument(); const doc2 = DocumentApp.openById('DOCUMENT_ID'); const nieuw = DocumentApp.create('Nieuw Document'); Logger.log(doc.getUrl()); ``` Een document is opgebouwd als een element-boom. De `Body` is de wortel, en elke alinea, tabel of afbeelding is een kind. Met `body.getNumChildren()` en `body.getChild(index)` doorloop je die structuur. ## Tekst toevoegen en opmaken ```javascript function voegTekstToe() { const doc = DocumentApp.openById('DOCUMENT_ID'); const body = doc.getBody(); body.appendParagraph('Hoofdstuk 1: Introductie') .setHeading(DocumentApp.ParagraphHeading.HEADING1); body.appendParagraph('Dit is een alinea tekst in het document.'); const alinea = body.appendParagraph(''); alinea.appendText('Normale tekst, '); alinea.appendText('vette tekst').setBold(true); alinea.appendText(' en '); alinea.appendText('cursieve tekst').setItalic(true); alinea.appendText(' hier.'); doc.saveAndClose(); } ``` `appendText()` geeft een `Text`-element terug, zodat je opmaak zoals `setBold()` en `setItalic()` direct op het zojuist toegevoegde stukje tekst toepast. ## Opmaakstijlen toepassen ```javascript function pasOpmaakToe() { const body = DocumentApp.getActiveDocument().getBody(); const alinea = body.appendParagraph('Gestylede paragraaf'); const stijl = {}; stijl[DocumentApp.Attribute.FONT_FAMILY] = 'Google Sans'; stijl[DocumentApp.Attribute.FONT_SIZE] = 14; stijl[DocumentApp.Attribute.FOREGROUND_COLOR] = '#1A73E8'; stijl[DocumentApp.Attribute.BOLD] = false; alinea.setAttributes(stijl); alinea.setAlignment(DocumentApp.HorizontalAlignment.CENTER); alinea.setSpacingBefore(12); alinea.setSpacingAfter(6); alinea.setLineSpacing(1.5); } ``` :::info Opmaak is altijd een eigenschap van het element, niet van de cursor. Stel stijlen daarom toe na het toevoegen van de tekst, anders heeft het element nog geen inhoud om op te maken. ::: ## Tabellen invoegen en beheren ```javascript function voegTabelToe() { const body = DocumentApp.getActiveDocument().getBody(); const tableData = [ ['Naam', 'Afdeling', 'Score'], ['Anna Jansen', 'Sales', '95'], ['Bob de Vries', 'IT', '88'], ['Carmen Smit', 'HR', '91'], ]; const tabel = body.appendTable(tableData); const headerRij = tabel.getRow(0); for (let k = 0; k < headerRij.getNumCells(); k++) { const cel = headerRij.getCell(k); cel.setBackgroundColor('#1A73E8'); cel.editAsText().setForegroundColor('#FFFFFF').setBold(true); } tabel.setBorderColor('#DADCE0'); } ``` `appendTable()` accepteert een tweedimensionale array van strings, waarbij elke binnenste array een rij is. Cellen maak je los op met `getCell(rij, kolom)` of via een rij met `getRow(i).getCell(k)`. ## Sjablonen verwerken (mail merge) Een veelgebruikt patroon is een sjabloondocument met placeholders, dat je per ontvanger kopieert en invult. ```javascript function verwerkSjabloon() { const sjabloonId = 'SJABLOON_DOCUMENT_ID'; const data = { '{{NAAM}}': 'Anna Jansen', '{{BEDRIJF}}': 'Cloud Captains', '{{DATUM}}': Utilities.formatDate(new Date(), 'Europe/Amsterdam', 'dd-MM-yyyy'), '{{BEDRAG}}': '€ 1.250,00', }; const kopie = DriveApp.getFileById(sjabloonId) .makeCopy('Contract - Anna Jansen', DriveApp.getFolderById('MAP_ID')); const doc = DocumentApp.openById(kopie.getId()); const body = doc.getBody(); Object.entries(data).forEach(([placeholder, waarde]) => { body.replaceText(placeholder, waarde); }); doc.saveAndClose(); Logger.log(doc.getUrl()); } ``` :::warn title="replaceText gebruikt reguliere expressies" Het eerste argument van `replaceText()` is een regex-patroon, geen letterlijke string. Tekens zoals `{`, `}`, `.`, `(` en `$` hebben een speciale betekenis. Gebruik placeholders zonder regex-tekens, of escape ze met een backslash, bijvoorbeeld `\\{\\{NAAM\\}\\}`. In de praktijk werken vierkante markers zoals `[NAAM]` of `<>` voorspelbaarder. ::: ## Inhoudsopgave en bladwijzers ```javascript function voegInhoudsopgaveToe() { const doc = DocumentApp.getActiveDocument(); const body = doc.getBody(); body.appendParagraph('Inhoudsopgave') .setHeading(DocumentApp.ParagraphHeading.HEADING1); body.appendTableOfContents(); const sectie = body.appendParagraph('Sectie 1'); sectie.setHeading(DocumentApp.ParagraphHeading.HEADING2); const positie = doc.newPosition(sectie.getChild(0), 0); doc.addBookmark(positie); } ``` Een bladwijzer hangt aan een `Position`, niet aan een tekst-index. Maak die positie met `doc.newPosition(element, offset)` en geef hem door aan `doc.addBookmark()`. Voor een benoemd bereik gebruik je `doc.addNamedRange(naam, range)`, waarbij je het bereik opbouwt met `doc.newRange()`. ## Afbeeldingen invoegen ```javascript function voegAfbeeldingIn() { const body = DocumentApp.getActiveDocument().getBody(); const afbeeldingUrl = 'https://example.com/logo.png'; const blob = UrlFetchApp.fetch(afbeeldingUrl).getBlob(); const afbeelding = body.appendImage(blob); afbeelding.setWidth(300); afbeelding.setHeight(150); const driveBlob = DriveApp.getFileById('AFBEELDING_ID').getBlob(); body.insertImage(0, driveBlob); } ``` :::tip title="Sla je werk expliciet op" `saveAndClose()` schrijft wijzigingen weg en sluit het document. Bij langere scripts roep je deze methode aan voordat je de URL deelt of het bestand verstuurt, zodat de ontvanger de definitieve versie ziet. Voor het actieve document is dit meestal niet nodig, omdat Docs zelf opslaat. ::: :::howto title="Automatisch contracten genereren vanuit een spreadsheet" 1. Maak een Google Docs sjabloon met placeholders zoals `[NAAM]` en `[DATUM]`. 2. Lees de contractdata uit een spreadsheet met `SpreadsheetApp`. 3. Maak voor elke rij een kopie van het sjabloon met `DriveApp.getFileById().makeCopy()`. 4. Open de kopie met `DocumentApp.openById()`. 5. Vervang alle placeholders met `body.replaceText(placeholder, waarde)`. 6. Roep `doc.saveAndClose()` aan en stuur de link per e-mail met `GmailApp.sendEmail()`. ::: DocumentApp vormt samen met DriveApp en GmailApp een krachtige combinatie voor documentworkflows. Zo bouw je een volledig geautomatiseerde pipeline die data ophaalt, documenten genereert en deze direct deelt of verstuurt, zonder handmatige tussenkomst. :::faq ### Hoe voeg ik een pagina-einde in? Gebruik `body.appendPageBreak()` om een pagina-einde toe te voegen na het laatste element. ### Kan ik een bestaand document leegmaken en opnieuw vullen? Ja. Gebruik `body.clear()` om alle inhoud te verwijderen, waarna je verse content toevoegt. Let op dat dit ook bestaande opmaak en kopteksten in de body wist. ### Hoe lees ik tekst uit een document? Gebruik `body.getText()` voor alle platte tekst in een keer, of loop door `body.getParagraphs()` voor toegang per alinea. ### Waarom heeft mijn replaceText geen effect? Het zoekpatroon is een reguliere expressie. Als je placeholder regex-tekens bevat zoals accolades of punten, moet je die escapen. Markers zonder speciale tekens werken het betrouwbaarst. ### Wat is het verschil tussen openById en getActiveDocument? `getActiveDocument()` werkt alleen in een script dat aan een document is gekoppeld en geeft het document waarin het script draait. `openById()` opent elk document waar je toegang toe hebt, ook vanuit een losstaand script of een trigger. ### Hoe vermijd ik time-outs bij veel documenten? Apps Script heeft een maximale uitvoeringstijd per run. Verwerk grote batches in stukken en gebruik een tijdgestuurde trigger of een voortgangsmarker in een spreadsheet om verder te gaan waar je gebleven was. :::