0
# Column System
1
2
RevoGrid's column system provides comprehensive configuration for defining column behavior, appearance, and functionality including grouping, pinning, templates, and type definitions.
3
4
## Column Definitions
5
6
### Basic Column Interface
7
8
```typescript { .api }
9
interface ColumnRegular extends ColumnType {
10
prop?: ColumnProp;
11
pin?: DimensionColPin;
12
name?: DataFormat;
13
sortable?: boolean;
14
size?: number;
15
minSize?: number;
16
maxSize?: number;
17
readonly?: ReadOnlyFormat;
18
order?: Order;
19
autoSize?: boolean;
20
}
21
```
22
23
**Core Column Properties** { .api }
24
```typescript
25
type ColumnProp = string | number;
26
type DataFormat = any;
27
type DimensionColPin = 'colPinStart' | 'colPinEnd';
28
type Order = 'asc' | 'desc' | undefined;
29
```
30
31
### Column Configuration
32
33
**prop** { .api }
34
```typescript
35
prop?: ColumnProp
36
```
37
Maps column to data property. Used to reference data field in row objects.
38
39
**name** { .api }
40
```typescript
41
name?: DataFormat
42
```
43
Display name shown in column header. Can be string, number, or custom content.
44
45
**size** { .api }
46
```typescript
47
size?: number
48
```
49
Column width in pixels. Overrides default column size.
50
51
**minSize** { .api }
52
```typescript
53
minSize?: number
54
```
55
Minimum column width when resizing. Cannot be less than cell padding for performance.
56
57
**maxSize** { .api }
58
```typescript
59
maxSize?: number
60
```
61
Maximum column width when resizing or auto-sizing.
62
63
**pin** { .api }
64
```typescript
65
pin?: DimensionColPin
66
```
67
Pin column to start or end of grid. Pinned columns remain visible during horizontal scrolling.
68
69
**sortable** { .api }
70
```typescript
71
sortable?: boolean
72
```
73
Enable sorting for this column. Adds sort indicators and click handlers to header.
74
75
**readonly** { .api }
76
```typescript
77
readonly?: ReadOnlyFormat
78
```
79
Make column or specific cells readonly. Can be boolean or function returning boolean.
80
81
**order** { .api }
82
```typescript
83
order?: Order
84
```
85
Current sort order for the column.
86
87
**autoSize** { .api }
88
```typescript
89
autoSize?: boolean
90
```
91
Enable auto-sizing for this specific column.
92
93
## Column Types
94
95
### Reusable Column Types
96
97
Define reusable column configurations with shared properties:
98
99
```typescript { .api }
100
interface ColumnType extends ColumnProperties {
101
readonly?: ReadOnlyFormat;
102
cellProperties?: PropertiesFunc;
103
cellTemplate?: CellTemplateFunc<VNode>;
104
cellCompare?: CellCompareFunc;
105
size?: number;
106
minSize?: number;
107
maxSize?: number;
108
editor?: string | Edition.EditorCtr;
109
}
110
```
111
112
**Column Type Registry** { .api }
113
```typescript
114
columnTypes: {[name: string]: RevoGrid.ColumnType} = {}
115
```
116
117
```typescript
118
// Define reusable column types
119
grid.columnTypes = {
120
// Numeric column type
121
numeric: {
122
cellProperties: (params) => ({
123
class: 'numeric-cell'
124
}),
125
cellTemplate: (params) => {
126
const value = Number(params.model[params.prop]);
127
return <span class="number">{value.toLocaleString()}</span>;
128
},
129
editor: 'numeric',
130
size: 100
131
},
132
133
// Currency column type
134
currency: {
135
cellTemplate: (params) => {
136
const value = Number(params.model[params.prop]);
137
return <span class="currency">${value.toFixed(2)}</span>;
138
},
139
cellProperties: (params) => ({
140
class: 'currency-cell',
141
style: { textAlign: 'right' }
142
}),
143
size: 120
144
},
145
146
// Date column type
147
date: {
148
cellTemplate: (params) => {
149
const date = new Date(params.model[params.prop]);
150
return <span class="date">{date.toLocaleDateString()}</span>;
151
},
152
editor: 'date',
153
size: 150
154
}
155
};
156
```
157
158
### Applying Column Types
159
160
Reference column types in column definitions:
161
162
```typescript
163
grid.columns = [
164
{ prop: 'id', name: 'ID', type: 'numeric' },
165
{ prop: 'price', name: 'Price', type: 'currency' },
166
{ prop: 'createdAt', name: 'Created', type: 'date' },
167
// Override type properties
168
{
169
prop: 'amount',
170
name: 'Amount',
171
type: 'currency',
172
size: 140 // Override default currency size
173
}
174
];
175
```
176
177
## Column Grouping
178
179
### Grouped Columns
180
181
Create hierarchical column headers with grouped columns:
182
183
```typescript { .api }
184
interface ColumnGrouping {
185
children: ColumnDataSchema[];
186
name: DataFormat;
187
}
188
```
189
190
**ColumnDataSchema** { .api }
191
```typescript
192
type ColumnDataSchema = ColumnGrouping | ColumnRegular;
193
```
194
195
### Creating Column Groups
196
197
```typescript
198
grid.columns = [
199
{ prop: 'id', name: 'ID', size: 80 },
200
{
201
name: 'Personal Information',
202
children: [
203
{ prop: 'firstName', name: 'First Name', size: 120 },
204
{ prop: 'lastName', name: 'Last Name', size: 120 },
205
{ prop: 'email', name: 'Email', size: 200 }
206
]
207
},
208
{
209
name: 'Address',
210
children: [
211
{ prop: 'street', name: 'Street', size: 150 },
212
{ prop: 'city', name: 'City', size: 100 },
213
{ prop: 'zipCode', name: 'ZIP', size: 80 }
214
]
215
},
216
{ prop: 'phone', name: 'Phone', size: 120 }
217
];
218
```
219
220
### Nested Groups
221
222
Create multiple levels of grouping:
223
224
```typescript
225
grid.columns = [
226
{ prop: 'product', name: 'Product' },
227
{
228
name: 'Sales Data',
229
children: [
230
{
231
name: 'Q1',
232
children: [
233
{ prop: 'q1_jan', name: 'Jan', type: 'currency' },
234
{ prop: 'q1_feb', name: 'Feb', type: 'currency' },
235
{ prop: 'q1_mar', name: 'Mar', type: 'currency' }
236
]
237
},
238
{
239
name: 'Q2',
240
children: [
241
{ prop: 'q2_apr', name: 'Apr', type: 'currency' },
242
{ prop: 'q2_may', name: 'May', type: 'currency' },
243
{ prop: 'q2_jun', name: 'Jun', type: 'currency' }
244
]
245
}
246
]
247
}
248
];
249
```
250
251
## Column Pinning
252
253
### Pin Columns to Sides
254
255
Keep important columns visible during horizontal scrolling:
256
257
```typescript
258
grid.columns = [
259
// Pinned to start
260
{ prop: 'id', name: 'ID', pin: 'colPinStart', size: 80 },
261
{ prop: 'name', name: 'Name', pin: 'colPinStart', size: 150 },
262
263
// Regular scrollable columns
264
{ prop: 'description', name: 'Description', size: 300 },
265
{ prop: 'category', name: 'Category', size: 120 },
266
{ prop: 'status', name: 'Status', size: 100 },
267
268
// Pinned to end
269
{ prop: 'total', name: 'Total', pin: 'colPinEnd', type: 'currency' },
270
{ prop: 'actions', name: 'Actions', pin: 'colPinEnd', size: 120 }
271
];
272
```
273
274
### Pin Configuration
275
276
```typescript
277
// Pin programmatically
278
const columns = await grid.getColumns();
279
columns.forEach(column => {
280
if (column.prop === 'importantColumn') {
281
column.pin = 'colPinStart';
282
}
283
});
284
await grid.updateColumns(columns);
285
```
286
287
## Column Templates
288
289
### Cell Templates
290
291
Customize cell content rendering:
292
293
```typescript { .api }
294
type CellTemplateFunc<T> = (params: ColumnDataSchemaModel) => T;
295
```
296
297
**ColumnDataSchemaModel** { .api }
298
```typescript
299
interface ColumnDataSchemaModel {
300
prop: ColumnProp;
301
model: DataType;
302
column: ColumnRegular;
303
rowIndex: number;
304
data: DataSource;
305
}
306
```
307
308
```typescript
309
// Custom cell templates
310
grid.columns = [
311
{
312
prop: 'status',
313
name: 'Status',
314
cellTemplate: (params) => {
315
const status = params.model[params.prop];
316
const statusClass = `status-${status.toLowerCase()}`;
317
return <span class={statusClass}>{status}</span>;
318
}
319
},
320
{
321
prop: 'avatar',
322
name: 'Avatar',
323
cellTemplate: (params) => {
324
const url = params.model[params.prop];
325
return <img src={url} class="avatar" alt="User avatar" />;
326
}
327
},
328
{
329
prop: 'progress',
330
name: 'Progress',
331
cellTemplate: (params) => {
332
const value = params.model[params.prop];
333
return (
334
<div class="progress-container">
335
<div
336
class="progress-bar"
337
style={{ width: `${value}%` }}
338
></div>
339
<span class="progress-text">{value}%</span>
340
</div>
341
);
342
}
343
}
344
];
345
```
346
347
### Column Header Templates
348
349
Customize column header rendering:
350
351
```typescript { .api }
352
type ColumnTemplateFunc<T> = (params: ColumnTemplateModel) => T;
353
```
354
355
```typescript
356
grid.columns = [
357
{
358
prop: 'priority',
359
name: 'Priority',
360
columnTemplate: (params) => {
361
return (
362
<div class="priority-header">
363
<span>Priority</span>
364
<button
365
class="filter-btn"
366
onClick={() => showPriorityFilter()}
367
>
368
🔽
369
</button>
370
</div>
371
);
372
}
373
},
374
{
375
prop: 'amount',
376
name: 'Amount',
377
columnTemplate: (params) => {
378
return (
379
<div class="amount-header">
380
<span>Amount</span>
381
<small>USD</small>
382
</div>
383
);
384
}
385
}
386
];
387
```
388
389
## Column Properties
390
391
### Cell Properties
392
393
Apply dynamic properties to individual cells:
394
395
```typescript { .api }
396
type PropertiesFunc = (params: ColumnDataSchemaModel) => {[key: string]: any};
397
type ColPropertiesFunc = (params: ColumnTemplateModel) => {[key: string]: any};
398
```
399
400
```typescript
401
grid.columns = [
402
{
403
prop: 'amount',
404
name: 'Amount',
405
cellProperties: (params) => {
406
const value = params.model[params.prop];
407
return {
408
class: {
409
'positive': value > 0,
410
'negative': value < 0,
411
'zero': value === 0
412
},
413
style: {
414
fontWeight: value > 1000 ? 'bold' : 'normal',
415
color: value < 0 ? 'red' : 'inherit'
416
}
417
};
418
}
419
},
420
{
421
prop: 'status',
422
name: 'Status',
423
cellProperties: (params) => {
424
const status = params.model[params.prop];
425
return {
426
class: `status-${status}`,
427
'data-status': status,
428
title: `Status: ${status}`
429
};
430
}
431
}
432
];
433
```
434
435
### Column Properties
436
437
Apply properties to entire column headers:
438
439
```typescript
440
grid.columns = [
441
{
442
prop: 'priority',
443
name: 'Priority',
444
columnProperties: (params) => {
445
return {
446
class: 'priority-column',
447
style: {
448
backgroundColor: '#f0f0f0',
449
borderLeft: '3px solid #007acc'
450
}
451
};
452
}
453
}
454
];
455
```
456
457
## Column Operations
458
459
### Updating Columns
460
461
**getColumns** { .api }
462
```typescript
463
async getColumns(): Promise<RevoGrid.ColumnRegular[]>
464
```
465
466
**updateColumns** { .api }
467
```typescript
468
async updateColumns(cols: RevoGrid.ColumnRegular[]): Promise<void>
469
```
470
471
```typescript
472
// Get current columns
473
const currentColumns = await grid.getColumns();
474
475
// Modify columns
476
const updatedColumns = currentColumns.map(column => {
477
if (column.prop === 'amount') {
478
return {
479
...column,
480
size: 150,
481
cellTemplate: customAmountTemplate
482
};
483
}
484
return column;
485
});
486
487
// Update grid with modified columns
488
await grid.updateColumns(updatedColumns);
489
```
490
491
### Column Store Access
492
493
Access column store for direct manipulation:
494
495
**getColumnStore** { .api }
496
```typescript
497
async getColumnStore(type?: RevoGrid.DimensionCols): Promise<ColumnSource>
498
```
499
500
```typescript { .api }
501
interface ColumnSource {
502
// Column access
503
getColumns(): RevoGrid.ColumnRegular[];
504
setColumns(columns: RevoGrid.ColumnRegular[]): void;
505
506
// Individual column operations
507
getColumn(index: number): RevoGrid.ColumnRegular;
508
setColumn(index: number, column: RevoGrid.ColumnRegular): void;
509
510
// Column manipulation
511
addColumns(columns: RevoGrid.ColumnRegular[], startIndex?: number): void;
512
removeColumns(startIndex: number, count: number): void;
513
514
// Column reordering
515
moveColumn(fromIndex: number, toIndex: number): void;
516
517
// Utilities
518
refresh(): void;
519
getColumnByProp(prop: ColumnProp): RevoGrid.ColumnRegular | undefined;
520
}
521
```
522
523
### Dynamic Column Management
524
525
```typescript
526
class ColumnManager {
527
private grid: HTMLRevoGridElement;
528
529
constructor(grid: HTMLRevoGridElement) {
530
this.grid = grid;
531
}
532
533
async addColumn(column: RevoGrid.ColumnRegular, index?: number) {
534
const columnStore = await this.grid.getColumnStore();
535
536
if (index !== undefined) {
537
columnStore.addColumns([column], index);
538
} else {
539
const currentColumns = columnStore.getColumns();
540
columnStore.setColumns([...currentColumns, column]);
541
}
542
}
543
544
async removeColumn(prop: RevoGrid.ColumnProp) {
545
const columnStore = await this.grid.getColumnStore();
546
const columns = columnStore.getColumns();
547
const filteredColumns = columns.filter(col => col.prop !== prop);
548
columnStore.setColumns(filteredColumns);
549
}
550
551
async moveColumn(fromProp: RevoGrid.ColumnProp, toProp: RevoGrid.ColumnProp) {
552
const columnStore = await this.grid.getColumnStore();
553
const columns = columnStore.getColumns();
554
555
const fromIndex = columns.findIndex(col => col.prop === fromProp);
556
const toIndex = columns.findIndex(col => col.prop === toProp);
557
558
if (fromIndex >= 0 && toIndex >= 0) {
559
columnStore.moveColumn(fromIndex, toIndex);
560
}
561
}
562
563
async toggleColumnVisibility(prop: RevoGrid.ColumnProp) {
564
const columns = await this.grid.getColumns();
565
const updatedColumns = columns.map(column => {
566
if (column.prop === prop) {
567
return {
568
...column,
569
size: column.size === 0 ? 100 : 0 // Hide/show via size
570
};
571
}
572
return column;
573
});
574
575
await this.grid.updateColumns(updatedColumns);
576
}
577
}
578
```
579
580
## Column Sorting
581
582
### Sort Configuration
583
584
Enable sorting for individual columns:
585
586
```typescript
587
grid.columns = [
588
{ prop: 'name', name: 'Name', sortable: true },
589
{ prop: 'age', name: 'Age', sortable: true },
590
{ prop: 'email', name: 'Email', sortable: false }
591
];
592
```
593
594
### Programmatic Sorting
595
596
**updateColumnSorting** { .api }
597
```typescript
598
async updateColumnSorting(
599
column: RevoGrid.ColumnRegular,
600
index: number,
601
order: 'asc'|'desc',
602
additive: boolean
603
): Promise<RevoGrid.ColumnRegular>
604
```
605
606
```typescript
607
// Sort by single column
608
const nameColumn = grid.columns.find(col => col.prop === 'name');
609
await grid.updateColumnSorting(nameColumn, 0, 'asc', false);
610
611
// Multi-column sort
612
const ageColumn = grid.columns.find(col => col.prop === 'age');
613
await grid.updateColumnSorting(ageColumn, 1, 'desc', true);
614
615
// Clear sorting
616
await grid.clearSorting();
617
```
618
619
### Custom Sort Comparators
620
621
Define custom sorting logic:
622
623
```typescript { .api }
624
type CellCompareFunc = (a: any, b: any) => number;
625
```
626
627
```typescript
628
grid.columnTypes = {
629
customSort: {
630
cellCompare: (a, b) => {
631
// Custom comparison logic
632
const valueA = parseFloat(a) || 0;
633
const valueB = parseFloat(b) || 0;
634
return valueA - valueB;
635
}
636
}
637
};
638
639
grid.columns = [
640
{
641
prop: 'customValue',
642
name: 'Custom Value',
643
type: 'customSort',
644
sortable: true
645
}
646
];
647
```
648
649
## Column Events
650
651
### Column-Related Events
652
653
Listen for column-specific events:
654
655
```typescript
656
// Before columns are set
657
grid.addEventListener('beforecolumnsset', (event) => {
658
const columns = event.detail;
659
console.log('About to set columns:', columns);
660
661
// Modify columns before they're applied
662
const modifiedColumns = columns.map(col => ({
663
...col,
664
size: col.size || 120 // Ensure minimum width
665
}));
666
667
// Update event detail (if supported)
668
event.detail = modifiedColumns;
669
});
670
671
// After columns are applied
672
grid.addEventListener('aftercolumnsset', (event) => {
673
const { columns, order } = event.detail;
674
console.log('Columns applied:', columns);
675
console.log('Sort order:', order);
676
});
677
678
// Column resize events
679
grid.addEventListener('aftercolumnresize', (event) => {
680
const resizedColumns = event.detail;
681
console.log('Columns resized:', resizedColumns);
682
683
// Save column widths
684
this.saveColumnWidths(resizedColumns);
685
});
686
687
// Header click events
688
grid.addEventListener('headerclick', (event) => {
689
const column = event.detail;
690
console.log('Header clicked:', column);
691
692
// Custom header click handling
693
if (column.prop === 'actions') {
694
showColumnMenu(column);
695
}
696
});
697
```
698
699
## Usage Examples
700
701
### Complete Column Configuration
702
703
```typescript
704
class AdvancedColumnSetup {
705
private grid: HTMLRevoGridElement;
706
707
constructor(grid: HTMLRevoGridElement) {
708
this.grid = grid;
709
this.setupColumns();
710
}
711
712
private setupColumns() {
713
// Define column types
714
this.grid.columnTypes = {
715
currency: {
716
cellTemplate: (params) => {
717
const value = Number(params.model[params.prop]) || 0;
718
return <span class="currency">${value.toLocaleString('en-US', {
719
minimumFractionDigits: 2,
720
maximumFractionDigits: 2
721
})}</span>;
722
},
723
cellProperties: (params) => ({
724
class: 'text-right',
725
style: { fontFamily: 'monospace' }
726
}),
727
size: 120,
728
sortable: true
729
},
730
731
status: {
732
cellTemplate: (params) => {
733
const status = params.model[params.prop];
734
return (
735
<div class={`status-badge status-${status.toLowerCase()}`}>
736
{status}
737
</div>
738
);
739
},
740
size: 100
741
},
742
743
actions: {
744
cellTemplate: (params) => (
745
<div class="action-buttons">
746
<button onClick={() => this.editRow(params.rowIndex)}>
747
Edit
748
</button>
749
<button onClick={() => this.deleteRow(params.rowIndex)}>
750
Delete
751
</button>
752
</div>
753
),
754
readonly: true,
755
size: 120
756
}
757
};
758
759
// Configure columns with grouping and pinning
760
this.grid.columns = [
761
// Pinned identification columns
762
{
763
prop: 'id',
764
name: 'ID',
765
pin: 'colPinStart',
766
size: 80,
767
readonly: true,
768
sortable: true
769
},
770
771
// Main data group
772
{
773
name: 'Customer Information',
774
children: [
775
{ prop: 'firstName', name: 'First Name', size: 120, sortable: true },
776
{ prop: 'lastName', name: 'Last Name', size: 120, sortable: true },
777
{ prop: 'email', name: 'Email', size: 200, sortable: true }
778
]
779
},
780
781
// Financial data group
782
{
783
name: 'Financial Data',
784
children: [
785
{ prop: 'balance', name: 'Balance', type: 'currency' },
786
{ prop: 'creditLimit', name: 'Credit Limit', type: 'currency' },
787
{ prop: 'totalSpent', name: 'Total Spent', type: 'currency' }
788
]
789
},
790
791
// Status and actions (pinned to end)
792
{ prop: 'status', name: 'Status', type: 'status', pin: 'colPinEnd' },
793
{ prop: 'actions', name: 'Actions', type: 'actions', pin: 'colPinEnd' }
794
];
795
}
796
797
private editRow(rowIndex: number) {
798
// Implement edit functionality
799
console.log('Editing row:', rowIndex);
800
}
801
802
private deleteRow(rowIndex: number) {
803
// Implement delete functionality
804
console.log('Deleting row:', rowIndex);
805
}
806
}
807
808
// Usage
809
const columnSetup = new AdvancedColumnSetup(grid);
810
```
811
812
The column system provides extensive flexibility for creating sophisticated data presentations with custom templates, dynamic properties, and advanced functionality like grouping and pinning.