Search code examples
angulartypescriptpdfmake

How do I add content dynamically in pdfmake?


I want to generate pdfs with pdfmake dynamically. I got everything working but the creation of dynamic rows based on data.

I simplified my code in this example:

getDocumentDefinition(img: string, data: DataResponse, user: UserResponse): TDocumentDefinitions {
    return {
        header: this.header(img),
        content: this.document(data, user),
        styles: this.applyStyles(),
    };
}

private document(data: DataResponse, user: UserResponse) {
     let rowY = 252;
     return [
         // works
         this.createRow(55, rowY, 1, { m: 10, s: 30 }, [163, 205], rowY + 6)

         // not working in loop
         data.map((item) => this.createRow(55, rowY, item.version, { m: item.minutes, s: item.seconds }, [163, 205], rowY + 6)).map(() => rowY += 34),
     ];
}

private createRow(rowX: number, rowY: number, version: number, time: { m: number; s: number }, x: number[], y: number): Content {
     return [
         this.createTable(10, version, time, {x: rowX, y: rowY}),
         this.circle(),
         this.circle(),
     ];
}

private createTable(heights: number, version: number, time: { m: number, s: number }, position: { x: number; y: number }): Content {
     return {
         table: {
             widths: ['10%', '30%', '30%', '30%'],
                heights: heights,
                body: [
                  [
                     {
                         text: version,
                         fontSize: 10,
                         borderColor: ['white', 'white', 'white', '#B3CCE6'],
                      },
                      {
                         text: time.m + 'm ' + time.s + 's',
                         fontSize: 10,
                         borderColor: ['white', 'white', 'white', '#B3CCE6'],
                      },
                      {
                         text: '',
                         fontSize: 10,
                         borderColor: ['white', 'white', 'white', '#B3CCE6'],
                      },
                      {
                         text: '',
                         fontSize: 10,
                         borderColor: ['white', 'white', 'white', '#B3CCE6'],
                      },
                   ],
                ],
            },
            absolutePosition: position,
        };
}

The methode createRow works outside of any loop but as soon as it is generated dynamically (see example above), the returning value is empty. I tried all kinds of loops and things but I cannot make it work. I would like to add single rows like this if possible. Any ideas on how to fix this? Is it possible to add content based on an array with an unknown size?


Solution

    1. It looks like you're missing a comma in your return array in the document method, after this.createRow
    2. data.map() returns an array, and when you include it within another array, you end up with a nested array
    3. You have the same Y value for all dynamic rows; I believe it should be a dynamic value

    I'd suggest smth like this:

    private document(data: DataResponse, user: UserResponse) {
        let rowY = 252;
    
        const staticContent = [
            this.createRow(55, rowY, 1, { m: 10, s: 30 }, [163, 205], rowY + 6)
        ];
    
        const dynamicContent = data.map((item, index) => {
            let updatedRowY = rowY + index * someYIncrementValue; // Update this based on your needs
     
            return this.createRow(55, updatedRowY, item.version, { m: item.minutes, s: item.seconds }, [163, 205], updatedRowY + 6)
        });
    
        return [...staticContent, ...dynamicContent];
    }