0
# Hook System
1
2
Event-driven customization system for intercepting and modifying table rendering at various stages, enabling advanced customization and dynamic content generation.
3
4
## Capabilities
5
6
### Hook Data Classes
7
8
Base classes providing context information for hook functions.
9
10
#### HookData Class
11
12
Base hook data class providing table and document context.
13
14
```typescript { .api }
15
class HookData {
16
/** Reference to the table being rendered */
17
table: Table;
18
/** Current page number */
19
pageNumber: number;
20
/** Table settings */
21
settings: Settings;
22
/** jsPDF document instance */
23
doc: jsPDFDocument;
24
/** Current cursor position */
25
cursor: Pos | null;
26
27
constructor(doc: DocHandler, table: Table, cursor: Pos | null);
28
}
29
```
30
31
#### CellHookData Class
32
33
Extended hook data class for cell-specific events.
34
35
```typescript { .api }
36
class CellHookData extends HookData {
37
/** Reference to the current cell */
38
cell: Cell;
39
/** Reference to the current row */
40
row: Row;
41
/** Reference to the current column */
42
column: Column;
43
/** Section type: 'head', 'body', or 'foot' */
44
section: "head" | "body" | "foot";
45
46
constructor(
47
doc: DocHandler,
48
table: Table,
49
cell: Cell,
50
row: Row,
51
column: Column,
52
cursor: Pos | null
53
);
54
}
55
```
56
57
### Hook Function Types
58
59
Function signatures for different hook events.
60
61
```typescript { .api }
62
/** Page-level hook function */
63
type PageHook = (data: HookData) => void | boolean;
64
65
/** Cell-level hook function */
66
type CellHook = (data: CellHookData) => void | boolean;
67
```
68
69
### Hook Events
70
71
Available hook events for customizing table rendering behavior.
72
73
#### didParseCell Hook
74
75
Called after the plugin has finished parsing cell content. Use this to override content or styles for specific cells.
76
77
```typescript { .api }
78
/** Called when the plugin finished parsing cell content */
79
didParseCell?: CellHook;
80
```
81
82
**Usage Example:**
83
84
```typescript
85
autoTable(doc, {
86
head: [['Name', 'Amount', 'Status']],
87
body: [
88
['John Doe', '1500', 'active'],
89
['Jane Smith', '2300', 'inactive'],
90
],
91
didParseCell: (data) => {
92
const { cell, column } = data;
93
94
// Format currency
95
if (column.dataKey === 1) { // Amount column
96
const amount = parseFloat(cell.text[0]);
97
cell.text = [`$${amount.toLocaleString()}`];
98
}
99
100
// Style status column
101
if (column.dataKey === 2) { // Status column
102
if (cell.text[0] === 'active') {
103
cell.styles.textColor = [0, 128, 0];
104
cell.text = ['✓ Active'];
105
} else {
106
cell.styles.textColor = [128, 0, 0];
107
cell.text = ['✗ Inactive'];
108
}
109
}
110
},
111
});
112
```
113
114
#### willDrawCell Hook
115
116
Called before a cell is drawn. Use this to modify styling or positioning before rendering.
117
118
```typescript { .api }
119
/** Called before a cell or row is drawn */
120
willDrawCell?: CellHook;
121
```
122
123
**Usage Example:**
124
125
```typescript
126
autoTable(doc, {
127
head: [['Product', 'Stock', 'Price']],
128
body: [
129
['Laptop', '5', '999'],
130
['Phone', '0', '599'],
131
['Tablet', '12', '399'],
132
],
133
willDrawCell: (data) => {
134
const { cell, column, doc } = data;
135
136
// Highlight low stock items
137
if (column.dataKey === 1) { // Stock column
138
const stock = parseInt(cell.text[0]);
139
if (stock === 0) {
140
cell.styles.fillColor = [255, 200, 200]; // Light red
141
cell.styles.fontStyle = 'bold';
142
} else if (stock < 10) {
143
cell.styles.fillColor = [255, 255, 200]; // Light yellow
144
}
145
}
146
147
// Apply custom jsPDF styling
148
if (column.dataKey === 2) { // Price column
149
doc.setTextColor(0, 100, 0); // Dark green for prices
150
}
151
},
152
});
153
```
154
155
#### didDrawCell Hook
156
157
Called after a cell has been drawn. Use this to add additional content like images, shapes, or custom text.
158
159
```typescript { .api }
160
/** Called after a cell has been added to the page */
161
didDrawCell?: CellHook;
162
```
163
164
**Usage Example:**
165
166
```typescript
167
autoTable(doc, {
168
head: [['Name', 'Rating', 'Notes']],
169
body: [
170
['Product A', '5', 'Excellent quality'],
171
['Product B', '3', 'Average'],
172
['Product C', '4', 'Good value'],
173
],
174
didDrawCell: (data) => {
175
const { cell, column, doc } = data;
176
177
// Draw star ratings
178
if (column.dataKey === 1) { // Rating column
179
const rating = parseInt(cell.text[0]);
180
const startX = cell.x + 5;
181
const centerY = cell.y + cell.height / 2;
182
183
// Draw stars
184
for (let i = 0; i < 5; i++) {
185
const x = startX + (i * 10);
186
if (i < rating) {
187
doc.setFillColor(255, 215, 0); // Gold
188
doc.circle(x, centerY, 3, 'F');
189
} else {
190
doc.setDrawColor(200, 200, 200);
191
doc.circle(x, centerY, 3, 'S');
192
}
193
}
194
}
195
196
// Add custom borders
197
if (column.dataKey === 2) { // Notes column
198
doc.setDrawColor(100, 100, 100);
199
doc.setLineWidth(0.5);
200
doc.line(cell.x, cell.y, cell.x + cell.width, cell.y);
201
}
202
},
203
});
204
```
205
206
#### willDrawPage Hook
207
208
Called before starting to draw content on a page. Use this to add headers, watermarks, or page setup.
209
210
```typescript { .api }
211
/** Called before starting to draw on a page */
212
willDrawPage?: PageHook;
213
```
214
215
**Usage Example:**
216
217
```typescript
218
autoTable(doc, {
219
head: [['Item', 'Quantity', 'Price']],
220
body: largeDataSet,
221
willDrawPage: (data) => {
222
const { doc, table, pageNumber } = data;
223
224
// Add header to each page
225
doc.setFontSize(16);
226
doc.setFont('helvetica', 'bold');
227
doc.text('Sales Report', 20, 20);
228
229
// Add page number
230
doc.setFontSize(10);
231
doc.setFont('helvetica', 'normal');
232
doc.text(`Page ${pageNumber}`, 200, 20);
233
234
// Add watermark
235
doc.setTextColor(200, 200, 200);
236
doc.setFontSize(48);
237
doc.text('DRAFT', 105, 150, {
238
angle: 45,
239
align: 'center'
240
});
241
242
// Reset text color for table content
243
doc.setTextColor(0, 0, 0);
244
doc.setFontSize(10);
245
},
246
});
247
```
248
249
#### didDrawPage Hook
250
251
Called after the plugin has finished drawing everything on a page. Use this to add footers, signatures, or final page elements.
252
253
```typescript { .api }
254
/** Called after the plugin has finished drawing everything on a page */
255
didDrawPage?: PageHook;
256
```
257
258
**Usage Example:**
259
260
```typescript
261
autoTable(doc, {
262
head: [['Description', 'Amount']],
263
body: invoiceItems,
264
didDrawPage: (data) => {
265
const { doc, table, pageNumber, cursor } = data;
266
267
// Add footer
268
const pageHeight = doc.internal.pageSize.height;
269
const pageWidth = doc.internal.pageSize.width;
270
271
doc.setFontSize(8);
272
doc.setTextColor(100, 100, 100);
273
274
// Company information
275
doc.text('MyCompany Inc.', 20, pageHeight - 20);
276
doc.text('123 Business St, City, State 12345', 20, pageHeight - 15);
277
doc.text('Phone: (555) 123-4567', 20, pageHeight - 10);
278
279
// Page number and date
280
doc.text(`Page ${pageNumber}`, pageWidth - 50, pageHeight - 20);
281
doc.text(new Date().toLocaleDateString(), pageWidth - 50, pageHeight - 15);
282
283
// Add total on last page
284
if (cursor && cursor.y > pageHeight - 100) {
285
const totalY = cursor.y + 10;
286
doc.setFontSize(12);
287
doc.setFont('helvetica', 'bold');
288
doc.text('Total: $1,234.56', pageWidth - 80, totalY);
289
}
290
},
291
});
292
```
293
294
### Hook Properties Interface
295
296
Collection of all hook functions for a table.
297
298
```typescript { .api }
299
interface HookProps {
300
didParseCell: CellHook[];
301
willDrawCell: CellHook[];
302
didDrawCell: CellHook[];
303
willDrawPage: PageHook[];
304
didDrawPage: PageHook[];
305
}
306
```
307
308
### Advanced Hook Patterns
309
310
#### Conditional Content Modification
311
312
```typescript
313
const didParseCell = (data: CellHookData) => {
314
const { cell, column, row, section } = data;
315
316
// Only modify body cells
317
if (section !== 'body') return;
318
319
// Format dates in specific column
320
if (column.dataKey === 'date') {
321
const date = new Date(cell.text[0]);
322
cell.text = [date.toLocaleDateString()];
323
}
324
325
// Add row numbers
326
if (column.index === 0) {
327
cell.text = [`${row.index + 1}. ${cell.text[0]}`];
328
}
329
};
330
```
331
332
#### Dynamic Styling Based on Data
333
334
```typescript
335
const willDrawCell = (data: CellHookData) => {
336
const { cell, row, table } = data;
337
338
// Alternate row colors differently for each section
339
switch (data.section) {
340
case 'head':
341
cell.styles.fillColor = [52, 73, 94];
342
cell.styles.textColor = [255, 255, 255];
343
break;
344
345
case 'body':
346
if (row.index % 2 === 0) {
347
cell.styles.fillColor = [245, 245, 245];
348
}
349
break;
350
351
case 'foot':
352
cell.styles.fillColor = [52, 152, 219];
353
cell.styles.textColor = [255, 255, 255];
354
cell.styles.fontStyle = 'bold';
355
break;
356
}
357
};
358
```
359
360
#### Multi-Page Headers and Footers
361
362
```typescript
363
let pageCount = 0;
364
365
const willDrawPage = (data: HookData) => {
366
pageCount++;
367
const { doc } = data;
368
369
// Different header for first page
370
if (pageCount === 1) {
371
doc.setFontSize(20);
372
doc.text('Annual Report 2024', 20, 30);
373
doc.setFontSize(12);
374
doc.text('Confidential Document', 20, 40);
375
} else {
376
doc.setFontSize(12);
377
doc.text('Annual Report 2024 (Continued)', 20, 20);
378
}
379
};
380
381
const didDrawPage = (data: HookData) => {
382
const { doc, pageNumber } = data;
383
const pageHeight = doc.internal.pageSize.height;
384
385
// Page footer with different content for last page
386
if (pageNumber === pageCount) {
387
doc.text('End of Report', 20, pageHeight - 10);
388
} else {
389
doc.text('Continued on next page...', 20, pageHeight - 10);
390
}
391
};
392
```
393
394
#### Hook Return Values
395
396
Hooks can return `false` to prevent default behavior:
397
398
```typescript
399
const willDrawCell = (data: CellHookData) => {
400
const { cell, column } = data;
401
402
// Skip drawing empty cells
403
if (!cell.text[0] || cell.text[0].trim() === '') {
404
return false; // Prevents cell from being drawn
405
}
406
407
// Skip drawing specific columns
408
if (column.dataKey === 'internal_id') {
409
return false;
410
}
411
};
412
```
413
414
### Position and Cursor Information
415
416
```typescript { .api }
417
type Pos = { x: number; y: number };
418
```
419
420
Hook functions receive cursor position information for precise element placement:
421
422
```typescript
423
const didDrawCell = (data: CellHookData) => {
424
const { cell, doc, cursor } = data;
425
426
console.log(`Cell position: (${cell.x}, ${cell.y})`);
427
console.log(`Cell size: ${cell.width} x ${cell.height}`);
428
console.log(`Cursor position: (${cursor?.x}, ${cursor?.y})`);
429
430
// Use position for custom drawing
431
doc.circle(cell.x + cell.width - 5, cell.y + 5, 2, 'F');
432
};
433
```