Repeat PDF pages with the Anvil PDF filling API
Tags: webdev, tutorial, javascript, pdf
Published: 2021-05-06 14:55:48


An oft-requested feature of the PDF filling API is to repeat pages within a PDF. You may have a PDF that has a page with a fixed list of empty fields, but more data than fits into the list of fields. We often see this with invoices, insurance documents, financial paperwork requiring beneficiaries, etc.

For example, here's the main block of an invoice template:

![invoice pdf lines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6kfbuhjxv9w4xdpkmfo.png)

It only has room for 6 items. But what if you need to generate this invoice with 10 line items? The PDF is static! The table will not grow to accept the necessary 10 items. What do you do?

Repeat the page with the remaining items!

Anvil's PDF filling API endpoint now supports PDF page repeating. You can repeat any page in any PDF, even pages in the middle of a multi-page PDF. Let's see it in action.

## Set up your template for repeats

We'll use the invoice mentioned above as an example. First [sign up for Anvil](https://app.useanvil.com/signup), then [get your API keys](https://www.useanvil.com/docs/api/getting-started#api-key).

You can use the same [invoice template PDF](https://github.com/anvilco/public-assets/blob/8e80eb6928f41c75a50a63dd3be084cd8cd71c9a/devto/invoice-template.pdf) I am using to follow along. [Upload the PDF](https://www.useanvil.com/docs/api/fill-pdf#creating-a-pdf-template) to your PDF template library in the Anvil dashboard. After upload, you'll see something like:

![invoice pdf template](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tx2hyvf8cbz04c6s1kcm.png)

To enable the page repeating in this invoice scenario, a new feature allows you to create an __Array__ with any number of children fields. We will be creating an array for _each column_ in the invoice table: `Description`, `Quantity`, `Unit Price`, `Amount`, then we'll send each column's array an `Array` of data to fill the PDF.

To create an array, make sure you have your template [in edit mode](https://www.useanvil.com/docs/api/fill-pdf#creating-a-pdf-template), click on the first item in your array, then move to the field editor's advanced tab:

![create array field](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dp75q098whh1ne3eydsr.png)

Click `Create an array`, for each item in the array, click `add another item`, then click the item you want to add. When you're done, it will look like this:

![array field created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wzspa4fe4d74cgmloqe.png)

Back on the options tab, you can set the `id` of the array field for easy filling. For example, I set it to `amounts` for this column:

![alias id set](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zx7u5xyta9q7h2yg4kk.png)

Now you can send this column an array of data to fill some or all of the fields. Click over to the template page's [API info tab](https://www.useanvil.com/docs/api/fill-pdf#creating-a-pdf-template) to see the payload to fill this array:

```js
{
  "title": "Invoice 1234",
  "textColor": "#CC0000",
  "data": {
    "invoiceId": "#1234",
    "amounts": [
      1.11,
      2.22,
      3.33,
      4.44,
      5.55,
      6.66,
    ]
  }
}
```

[POSTing to the PDF template](https://www.useanvil.com/docs/api/fill-pdf#filling-a-pdf-template) with the data above yields all amounts filled. Item `[0]` will go in the first box, item `[1]` in the second, etc.

![invoice amounts filled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t96ds0f997skedf4jub8.png)

Now set up the other columns&mdash;`Description`, `Quantity`, `Unit Price`&mdash; the same way you did with the `Amounts` and you'll be off to the races.

```js
{
  "title": "Invoice 1234",
  "textColor": "#CC0000",
  "data": {
    "invoiceId": "#1234",
    "descriptions": [
      'Widget #1',
      'Widget #2',
      'Widget #3',
      'Widget #4',
      'Widget #5',
      'Widget #6'
    ],
    "quantities": [1, 2, 3, 4, 5, 6],
    "unitPrices": [1.11, 2.22, 3.33, 4.44, 5.55, 6.66],
    "amounts": [1.11, 4.44, 9.99, 17.76, 27.75, 39.96]
  }
}
```

![all invoice columns](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0odsko4rqb0prqtlltuj.png)

## Repeating the page

Once your template is set up, repeating a page is super simple:

*__Send an array of data with more items than spaces available in the PDF’s Array field.__*

The previous examples had only 6 items in each array. Sending any additional items will tell Anvil to repeat the page. It will repeat the page until all items in your array are rendered on a page.

```js
{
  "title": "Invoice 1234",
  "textColor": "#CC0000",
  "data": {
    "invoiceId": "#1234",
    "descriptions": [
      'Widget #1',
      'Widget #2',
      'Widget #3',
      'Widget #4',
      'Widget #5',
      'Widget #6',
      'Widget #7' // Extra item!
    ],
    "quantities": [1, 2, 3, 4, 5, 6, 7],
    "unitPrices": [1.11, 2.22, 3.33, 4.44, 5.55, 6.66, 7.77],
    "amounts": [1.11, 4.44, 9.99, 17.76, 27.75, 39.96, 54.39]
  }
}
```

![pdf invoice page repeating](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iv1sfowddopxot3vau7v.png)

Note that non-array data like `Invoice ID` above is repeated across all pages. There are ways to control this, but we'll cover them in subsequent blog posts.

## Filling page numbers

You may have noticed the page numbers in the screenshot above. Page numbers can be injected into the PDF as well.

First make sure your template is in order. All you need is a field or fields for the page number, total, etc. These are just _Short Text_ fields&mdash;no special setup necessary. I've given mine `id`s of `pageNumber` and `totalPages`:

![pdf page field](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wcn75wzohak9mvai2b92.png)

Now send those fields a template string with a page number variable e.g. `'{{pageNumber}}'`

```js
{
  "title": "Invoice 1234",
  "textColor": "#CC0000",
  "data": {
    "invoiceId": "#1234",
    "amounts": [1.11, 4.44, 9.99, 17.76, 27.75, 39.96, 54.39]
    ...
    "pageNumber": '{{pageNumber}}',
    "totalPages": '{{totalPages}}'
  }
}
```

Anvil will replace these variables with the correct data for each rendered page.

![pdf page numbers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acdqjg0yzdycmd9zgzo1.png)

Template strings can be used to fill any Short Text or Long Text field. Several page-related variables are supported in template strings

* `pageNumber` - Page number within the PDF
* `pageIndex` - 0-based `pageNumber`, i.e. `pageNumber - 1`
* `totalPages` -  Total number of pages in the PDF
* `pageRepeatNumber` - Page number _within this repeat loop_. It will be `1` if there is no repeating
* `pageRepeatIndex` - 0-based `pageRepeatNumber`
* `pageRepeatTotal` - Total number of pages within this repeat loop

Any number of these variables can be combined to output onto a single field. Just put them in the same string! For example, here is a Short Text field I've created called `pageNumberAll`.

![pdf all page numbers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4hwc898roy9eyomzt8f.png)

Simply send up a string using multiple variables:

```js
{
  "title": "Invoice 1234",
  "textColor": "#CC0000",
  "data": {
    "invoiceId": "#1234",
    ...
    "pageNumberAll": 'Page {{pageNumber}} of {{totalPages}}',
  }
}
```

And it outputs in one field:

![pdf all page numbers output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8em7elo3dodm3slzg6cf.png)

## Conclusion

Filling a PDF with arbitrary-length data is an example of a situation where a physical process (with paper) is challenging to replicate in a software environment. Now you can repeat those PDF pages and fill all your fixed documents without worry.

Having covered some of the fundamental ways to manage page repeats within a PDF, we’ll be diving deeper into the more complex ways in subsequent blog posts. For now, check out the [PDF filling API guide](https://www.useanvil.com/docs/api/fill-pdf) if you haven't already.

If you’re developing something cool with PDFs and/or paperwork automation, we’d love to hear more from you! Let us know at [developers@useanvil.com](mailto:developers@useanvil.com).