Recently I was asked by a client whether we could produce a PDF catalog from his company’s database, with products grouped by manufacturer. Me: “Of course, this is FileMaker.” Him: “Can it have a table of contents?” Me: “Yeah, sure, no problem.”
Actually, it took some trial and error, but we got there eventually…
…and we’re going to look at a simplified version with sample data in today’s demo file: pdf-catalog-with-toc
In addition to producing a table of contents, we need to…
- Assemble multiple separate “print jobs” into a single PDF
(front cover, TOC, product listing, back cover)
- Make sure FileMaker page numbers are consistent with PDF page numbers
(if the front cover + TOC take up 4 pages, then “page one” of the product listing will actually be page 5)
- Display a conditional header for vendor product groups that span multiple pages
(don’t show products on a given page without making it clear who the vendor is)
- Allow catalog to be generated from any found set of products
(don’t assume that a catalog always consists of all products for all vendors)
- Make sure technique is multi-user friendly
(user A can generate one catalog, while user B simultaneously generates another)
…but I think the most interesting challenge is the generation of the table of contents. The product listing looks like this…
…and it will provide the basis for the TOC page numbers. The TOC is a list view in the vendor table…
…with toc_page_number defined thus:
And this will work because the scripted routine we’re going to look at below will create one variable per vendor id in the TOC.
Also, since a catalog may be generated from a subset of product records, we need to calculate the “page offset” at run time, rather than assuming the TOC will always be three pages long. Reminder: the purpose of the page offset is to ensure a) that page numbers on the TOC are correct, and b) that FileMaker page numbering jibes with the PDF reader’s.
Here’s the definintion of product::page_number:
When it comes time to generate the TOC, we’re going to “consume” the product listing from the bottom up, looping through the found set backward, popping back and forth between browse and preview modes, omitting records as we go, and declaring variables “dynamically” (which you can read about in depth in Dynamic Variable Instantiation) so we end up with a $variable for each vendor foreign key corresponding to the page where their listing begins.
At any rate, you can see for yourself in the “generate pdf” script, which is extensively commented (at least according to my minimalist standards). Here’s the middle portion…
Incidentally, the unsung hero of today’s demo is the product::running_count field, which is defined thus…
…and which not only makes it easy to know how many records to omit during TOC generation, but also instructs conditional headers to only appear when a vendor’s products span multiple pages…
…i.e., show it most of the time, but hide it under these conditions:
Well, as the old saying goes, there are many ways to skin a cat(alog). If you’ve grappled with this issue, and come up with an approach you prefer to this one, I hope you’ll post a comment or send me a demo — or better yet, both.
8 thoughts on “PDF Catalog with Table of Contents”
Really nice work – as usual!
Hm – I wonder about … an Index?
Thanks Bruce… that’s a great idea, and I accept your offer to write the code :-)
I’m thinking about it. Since an Index comes AFTER the main content it may actually be a bit easier to generate.
Thank you, thank you! This made my day. I just used your basic technique to add page numbers to the Index in a student directory. And, yes, it was easier than the TOC. :) Aloha ~~
Hi, thanks for the useful tutorial. Maybe it’s a stupid question but there is a thing that I don’t understand how is done… in the TOC there are the dots that separate the vendor from the page numbers, and that dots are variable in order to have page numbers aligned on the right… How did you do it? What do I have to insert in the text field to achieve that? thank you
You need to a) insert a single tab character and then b) format the tab stop via the Inspector like so:
Wow thank you Kevin!!!
You are welcome!