GridColumn<T>

Each entry in the [columns] array is a GridColumn<T> object, where T is the row data type. Only key is required — every other property has a safe default or is simply omitted when not needed.

import { GridColumn } from '@gridcraft/angular';

interface Employee {
  id:         number;
  firstName:  string;
  lastName:   string;
  department: string;
  salary:     number;
}

const columns: GridColumn<Employee>[] = [
  // Only key is required — everything else is optional
  { key: 'firstName', name: 'First Name', prop: 'firstName', width: 160 },
  { key: 'lastName',  name: 'Last Name',  prop: 'lastName',  width: 160 },
  { key: 'dept',      name: 'Department', prop: 'department', sizing: 'flex' },
  { key: 'salary',    name: 'Salary',     prop: 'salary',    width: 120 },
];

Identity & data

PropertyTypeDefaultDescription
keystringREQUIREDUnique column identifier. Used as the sort key, filter key, and column persistence key. Must be unique within the columns array.
namestring—Header display label. Defaults to an empty string when omitted.
propkeyof T | string— Data path to read the cell value from the row object. Supports dot-notation for nested properties, e.g. 'address.city'. Omit when using valueGetter or a custom cellTemplate that reads the row directly.
valueGetter(row: T, col: GridColumn<T>) => any—Custom value resolver. Takes precedence over prop when both are set. Also used when exporting this column.

Sizing

PropertyTypeDefaultDescription
sizing'fixed' | 'flex' | 'auto''fixed' Column sizing mode. 'fixed' — exact px width, no growth. 'flex' — grows proportionally via flexGrow. 'auto' — fills remaining space equally with other auto columns.
widthnumber—Column width in px. Used when sizing is 'fixed'.
minWidthnumber—Minimum width in px. Enforced during drag-resize and respected by flex sizing. Defaults to 50 during resize operations.
maxWidthnumber—Maximum width in px. Enforced during drag-resize.
flexGrownumber1Flex-grow factor. Only used when sizing is 'flex'. A column with flexGrow: 2 claims twice as much space as one with flexGrow: 1.
resizablebooleanfalseShow a drag resize handle on this column's header cell. config.columnResize must also be true.

Positioning

PropertyTypeDefaultDescription
pin'left' | 'right'— Pin (stick) the column to the left or right edge. Pinned columns remain visible during horizontal scroll. Multiple left-pinned columns stack automatically with correct sticky offsets.
draggablebooleanfalseEnable drag-drop reorder for this column. config.columnReorder must also be true.
ordernumber—Initial render position. Lower values appear first. Overridden by persisted column state when config.persistColumns is set.

Sorting

PropertyTypeDefaultDescription
sortablebooleanfalseEnable click-to-sort on this column's header cell.
sortKeystringkeyThe key sent in SortConfig.key when this column is sorted. Useful when the server expects a different field name than col.key.
comparator(a, b, rowA, rowB, dir) => number—Custom client-side sort comparator. Receives both the resolved cell values and the full row objects. Return negative / zero / positive.

Visibility

PropertyTypeDefaultDescription
hiddenbooleanfalse Start the column hidden. Free to set, and reversible at any time through setState({ columns }).

Templates

Assign Angular TemplateRef instances (obtained via @ViewChild in the host component) to fully customise rendering for headers, cells, and summary rows. Each template receives a typed context object — see the context types section below.

PropertyTypeContextDescription
cellTemplateTemplateRefCellContext<T>Custom body cell renderer. Replaces the default text rendering for every data row in this column.
headerTemplateTemplateRefHeaderContext<T>Custom header cell renderer. Replaces the default label and sort icons.
subHeaderTemplateTemplateRefSummaryContext<T>Renders a summary row between the header and the first data row. Suitable for column sub-headings or aggregate values.
footerTemplateTemplateRefSummaryContext<T>Renders a summary row pinned below the last data row. Suitable for column totals or grand totals.
// In your component class:
@ViewChild('salaryCell')   salaryCell!:   TemplateRef<CellContext<Employee>>;
@ViewChild('statusHeader') statusHeader!: TemplateRef<HeaderContext<Employee>>;
@ViewChild('salaryFooter') salaryFooter!: TemplateRef<SummaryContext<Employee>>;

// Wrap in computed() so ViewChild refs are available at render time
readonly columns = computed((): GridColumn<Employee>[] => [
  {
    key:            'salary',
    name:           'Salary',
    prop:           'salary',
    width:          130,
    cellTemplate:   this.salaryCell,
    footerTemplate: this.salaryFooter,
  },
  {
    key:            'status',
    name:           'Status',
    width:          100,
    headerTemplate: this.statusHeader,
  },
]);

// In the component template:

// <ng-template #salaryCell let-value="value">
//   {{ value | currency:'USD':'symbol':'1.0-0' }}
// </ng-template>
//
// <ng-template #salaryFooter let-column="column">
//   Total: {{ total() | currency }}
// </ng-template>
//
// <ng-template #statusHeader let-column="column" let-sortDir="sortDir">
//   {{ column.name }}
//   @if (sortDir === 'asc') { ↑ } @else if (sortDir === 'desc') { ↓ }
// </ng-template>

Styling

PropertyTypeDefaultDescription
cellClassstring | (row: T, value: any) => string | Record<string, boolean>—Extra CSS class(es) applied to every body cell in this column. The function form receives the row object and resolved cell value per row.
headerClassstring—Extra CSS class applied to the header cell for this column.

Filtering

PropertyTypeDefaultDescription
filterColumnFilterConfig— Enable a filter control for this column. config.filterMode must also be set. Omit to show no filter control for this column.

ColumnFilterConfig properties

PropertyTypeDefaultDescription
type'text' | 'number' | 'date' | 'select' | 'set'REQUIREDDetermines the input control and default operators shown in the filter.
placeholderstring—Input placeholder text shown when the filter is empty.
operatorsFilterOperator[]type defaultsOverride the list of available filter operators shown in the operator dropdown.
options{ label: string; value: any }[]—Required when type is 'select'. Optional for 'set' — if omitted, unique values are extracted from loaded rows automatically.
fetchValues() => Observable<{ label: string; value: any }[]>—Used with type: 'set' only. Load the checklist values from the server on demand rather than extracting them from client-side rows.

Filter types:'text' — string operators (contains, equals, starts with, ends with, not contains). 'number' — numeric operators (=, ≠, >, ≥, <, ≤). 'date' — date operators (equals, before, after). 'select' — single-value dropdown from a static options list. 'set' — multi-value checklist (operator: in). Values can be static, extracted from rows, or fetched via fetchValues.

Inline editing

Set editable: true on a column to enable in-place cell editing. The interaction that triggers the editor is controlled by config.editTrigger (double-click by default). Committed edits emit (cellEditCommit) and are automatically added to the grid's undo/redo history (Ctrl+Z / Ctrl+Y).

PropertyTypeDefaultDescription
editableboolean | (row: T) => booleanfalseEnable inline editing for this column. Pass a function to make individual rows read-only (e.g. lock the header row in an editable spreadsheet).
editor'text' | 'number' | 'date' | 'checkbox' | 'select' | TemplateRef'text' Editor control type. Built-in controls auto-focus and commit on Enter/Tab. Pass a TemplateRef<EditorContext<T>> for a fully custom editor component.
editorOptions{ placeholder?, min?, max?, step?, options? }— Control-specific options. placeholder applies to text/number. min / max / step apply to number. options: { label, value }[] is required when editor: 'select'.
valueSetter(row: T, value: any) => T— Custom function to apply the new value to the row object. Must return the updated row (immutably). When omitted the grid does a shallow spread: { ...row, [prop]: value }. Use a valueSetter when the column uses a valueGetter or nested prop.

Grouping aggregation

When config.grouping is active, columns can display per-group aggregate values inside the group header row.

PropertyTypeDefaultDescription
aggregation'sum' | 'avg' | 'min' | 'max' | 'count' | (values, rows) => any— Aggregation shown inside each group header for this column. Built-in names resolve numerically (non-numeric values are ignored for sum/avg/min/max). Pass a custom function for any other calculation.
aggregationFormat(value: any) => string—Optional formatter applied to the aggregation result before display (e.g. v => '$' + v.toLocaleString()).

Export

PropertyTypeDefaultDescription
excludeFromExportbooleanfalseSet to true to omit this column from all CSV, Excel, and Word exports. Also omits it when exporting via the context menu.

Template context types

import {
  CellContext,
  HeaderContext,
  SummaryContext,
  ExpandContext,
} from '@gridcraft/angular';

// ── cellTemplate ─────────────────────────────────────────────
// Provides the full row and the resolved cell value.
interface CellContext<T = any> {
  $implicit: T;       // the row object — use "let-row" shorthand
  row:       T;
  value:     any;     // resolved via valueGetter → prop path → undefined
  column:    GridColumn<T>;
  rowIndex:  number;
}

// ── headerTemplate ────────────────────────────────────────────
// Provides the column definition and the active sort direction.
interface HeaderContext<T = any> {
  column:  GridColumn<T>;
  sortDir: 'asc' | 'desc' | null;
}

// ── subHeaderTemplate / footerTemplate ───────────────────────
// Provides only the column definition (no row data — these are summary rows).
interface SummaryContext<T = any> {
  column: GridColumn<T>;
}

// ── #gcExpandRow template (on <gridcraft>, not a column) ──
// Provides the parent row whose expand panel is being rendered.
interface ExpandContext<T = any> {
  $implicit: T;   // the row object — use "let-row" shorthand
  row:       T;
  rowIndex:  number;
}

Complete column definitions example

import { GridColumn, CellContext, SummaryContext } from '@gridcraft/angular';

const columns: GridColumn<Employee>[] = [
  // Fixed-width column: sort + text filter + resize
  {
    key:       'lastName',
    name:      'Last Name',
    prop:      'lastName',
    width:     160,
    minWidth:  80,
    sortable:  true,
    resizable: true,
    draggable: true,
    filter:    { type: 'text', placeholder: 'Search name…' },
  },

  // Flex column — fills remaining horizontal space
  {
    key:      'email',
    name:     'Email',
    prop:     'email',
    sizing:   'flex',
    flexGrow: 2,
    sortable: true,
    filter:   { type: 'text' },
  },

  // Number column with custom value getter and select filter
  {
    key:         'level',
    name:        'Level',
    width:        90,
    valueGetter: (row) => row.jobLevel ?? 1,
    sortable:    true,
    filter: {
      type:    'select',
      options: [
        { label: 'Junior', value: 1 },
        { label: 'Mid',    value: 2 },
        { label: 'Senior', value: 3 },
      ],
    },
    cellClass: (_row, value) => value >= 3 ? 'cell--senior' : '',
  },

  // Salary with custom templates + number filter
  {
    key:            'salary',
    name:           'Salary',
    prop:           'salary',
    width:           130,
    sortable:        true,
    filter:          { type: 'number', operators: ['>=', '<='] },
    cellTemplate:    this.salaryCellTpl,    // TemplateRef from @ViewChild
    footerTemplate:  this.salaryFooterTpl,
  },

  // Pinned action column hidden from export
  {
    key:               'actions',
    name:              '',
    width:              60,
    pin:               'right',
    cellTemplate:      this.actionsTpl,
    excludeFromExport: true,
  },
];