demo D52
Custom comparators: JavaScript Data Grid Demo
Sorting by priority words, versions, or a domain rule
value.compare
You are looking at an incident queue of two thousand rows where three columns carry an order the alphabet gets wrong. Sort Priority and it ranks by real severity rather than A to Z, sort Version and 2.10.0 lands after 2.9.0 not before it, and sort Owner and the unassigned rows stay at the bottom whichever way you sort.
The configuration
<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.css">
<script src="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.js"></script>
<div id="grid" style="height: 540px"></div>
<script>
// Worst first. The comparator reads positions out of this, not the strings.
const PRIORITIES = ['critical', 'high', 'medium', 'low', 'none'];
// Order by a known ladder rather than by the words themselves. Alphabetical
// gives critical, high, low, medium, none, which looks deliberate and is not.
const byPriority = (a, b) =>
PRIORITIES.indexOf(String(a)) - PRIORITIES.indexOf(String(b));
// Compare dotted release numbers as numbers, with pre-releases before the
// release they lead to. Text sort puts 1.10.0 before 1.9.3, and 2.0.0 before
// 2.0.0-rc.1, both the reverse of what shipping means.
function bySemver(a, b) {
const parse = (value) => {
const [core, pre = null] = String(value ?? '').split('-');
const parts = core.split('.').map((n) => Number(n) || 0);
return { parts, pre };
};
const left = parse(a);
const right = parse(b);
for (let i = 0; i < 3; i++) {
const diff = (left.parts[i] ?? 0) - (right.parts[i] ?? 0);
if (diff !== 0) return diff;
}
if (left.pre === right.pre) return 0;
// A version with no pre-release tag is the finished one, so it sorts after
// every candidate that carried the same numbers.
if (left.pre === null) return 1;
if (right.pre === null) return -1;
return left.pre < right.pre ? -1 : 1;
}
// Sort names, and keep the unassigned ones at the bottom in both directions.
// The grid inverts a comparator's result for a descending sort, so a blank
// that must stay last has to be pushed the other way when descending is set.
function ownersLast(a, b, _rowA, _rowB, descending) {
const blankA = a == null || a === '';
const blankB = b == null || b === '';
if (blankA && blankB) return 0;
if (blankA) return descending ? -1 : 1;
if (blankB) return descending ? 1 : -1;
const left = String(a);
const right = String(b);
return left < right ? -1 : left > right ? 1 : 0;
}
const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
rowKey: 'id',
columns: [
{ field: 'id', title: 'Incident', layout: { width: 130, pin: 'start' } },
{
field: 'priority', title: 'Priority',
layout: { width: 120 },
value: { compare: byPriority },
cell: {
decoration: 'pill',
variant: { map: { critical: 'danger', high: 'warning', medium: 'info', low: 'neutral', none: 'neutral' } },
},
},
{ field: 'version', title: 'Version', layout: { width: 150 }, value: { compare: bySemver } },
{ field: 'owner', title: 'Owner', layout: { width: 150 }, value: { compare: ownersLast } },
{ field: 'service', title: 'Service', filter: { type: 'set' } },
{ field: 'summary', title: 'Summary', layout: { flex: 1, min: 240 } },
{ field: 'ageHours', title: 'Age', type: 'number', format: { suffix: ' h' }, layout: { width: 110 } },
],
rows, // 2,000 incident records
});
</script>
Sorting by a custom comparator instead of default ordering
Default sorting compares values with the ordinary less-than rules for numbers and strings, which breaks down as soon as a column carries meaning a plain comparison cannot see: priority words that should read Low, Medium, High rather than alphabetically, semantic version strings where “2.10.0” needs to land after “2.9.0” rather than before it, or a domain-specific rank that only the application knows. A developer reaches for a custom comparator whenever the natural order of a column is not its lexical or numeric order. Lattice Grid exposes this through value.compare, a column option taking a function that receives two cell values and returns the same negative, zero, or positive result a standard JavaScript Array.prototype.sort comparator would, so existing comparator functions for version strings or ranked enums drop in without adaptation. The comparator runs only during a sort operation, not on every render, so attaching one to a column of custom-ranked categories costs nothing while the grid is idle and adds no overhead to scrolling or filtering. Sort state set through a custom comparator is a plain { col, dir } pair like any other sort, so it serialises the same way for a saved view or a shareable link, and the header retains its usual ascending and descending arrow regardless of how the ordering underneath it is computed.
How do I sort a column by custom logic instead of alphabetical or numeric order?
Set value.compare on the column definition to a function taking two cell values and returning negative, zero, or positive, the same contract as a standard array sort comparator. Lattice Grid calls it during the sort pass in place of the default comparison, so a column of priority labels or version strings sorts by the rule the function encodes rather than by character order.