Table of Contents

Headless data layer

Use the data layer independently — sort, filter, group, and export without any visual component on screen. Useful for background processing, batch exports, and unit-testable data pipelines.

Overview

TTMSFNCDataGridData is the layer that stores cell values and owns all data operations: sorting, filtering, grouping, and CSV export. Because it has no dependency on drawing or controls, you can instantiate it anywhere — including a background thread, a service, or a console application — and run full data operations without displaying anything.

The same API works on both the headless layer and on a live grid: Filter.Add, ApplyFilter, Sort, Group, Strings[], Floats[], Ints[], SaveToCSVData are all on TTMSFNCDataGridData and therefore available on TTMSFNCDataGrid too.

Quick example

Load 500 JSON records, filter by category, sort by price, and log the top five:

procedure TFormDataLayerDemo.BtnLoadClick(Sender: TObject);
begin
  FData.ClearData;
  FData.FixedRowCount       := 1;
  FData.Options.IO.StartRow := 1;   // row 0 receives JSON key names as headers

  FData.LoadFromJSONData(
    JSONPath,
    '', '',
    ['id', 'name', 'category', 'price', 'stock', 'is_organic', 'is_vegan']);

  Log(Format('Loaded %d records', [FData.RowCount - FData.FixedRowCount]));
end;

Step by step

1. Create and destroy

type
  TMyForm = class(TForm)
  private
    FData: TTMSFNCDataGridData;
  end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
  FData := TTMSFNCDataGridData.Create;
end;

procedure TMyForm.FormDestroy(Sender: TObject);
begin
  FData.Free;
end;

TTMSFNCDataGridData is an ordinary object — it allocates on the heap and must be freed explicitly.

2. Load data

The data layer supports the same load methods as the grid:

// From JSON (most common for REST payloads)
FData.LoadFromJSONData(FileName, '', '',
  ['id', 'name', 'category', 'price', 'stock']);

// From CSV
FData.Options.IO.Delimiter := ',';
FData.LoadFromCSVData('products.csv');

// Manually
FData.ColumnCount   := 3;
FData.FixedRowCount := 1;
FData.RowCount      := 4;
FData.Cells[0, 0] := 'ID';
FData.Cells[1, 0] := 'Name';
FData.Cells[2, 0] := 'Price';
FData.Cells[0, 1] := 1;  FData.Cells[1, 1] := 'Widget A';  FData.Cells[2, 1] := 9.99;
FData.Cells[0, 2] := 2;  FData.Cells[1, 2] := 'Widget B';  FData.Cells[2, 2] := 14.50;
FData.Cells[0, 3] := 3;  FData.Cells[1, 3] := 'Widget C';  FData.Cells[2, 3] := 4.25;

Set FData.Options.IO.StartRow := 1 before loading JSON so that row 0 receives the JSON key names as column headers automatically.

3. Filter

FData.Filter.Clear;
FData.Filter.Add(COL_CATEGORY, gftEqual, 'Meat');
FData.ApplyFilter;

After ApplyFilter, iterate visible rows with IsRowDisplayed:

var Count := 0;
for var R := FData.FixedRowCount to FData.RowCount - 1 do
  if FData.IsRowDisplayed(R) then
    Inc(Count);
Log(Format('%d matching rows', [Count]));

To remove all filters and show every row again, call RemoveFilter:

FData.RemoveFilter;

4. Sort

FData.Sort(COL_PRICE, gsdDescending);

Sort and filter interact: sorting re-orders only the displayed rows; hidden rows stay hidden.

5. Group with aggregations

FData.Group(COL_CATEGORY);
FData.GroupCount(COL_CATEGORY);   // count column
FData.GroupSum(COL_PRICE);        // sum column

Walk the result to inspect group rows and their summaries:

for var R := FData.FixedRowCount to FData.RowCount - 1 do
begin
  if FData.IsRowNode(R) then
    Log(FData.Strings[FData.FixedColumnCount, R])   // group header text
  else if FData.IsRowSummary(R) then
    Log(Format('  count=%.0f   sum=$%.2f',
      [FData.Floats[COL_CATEGORY, R], FData.Floats[COL_PRICE, R]]));
end;

FData.Ungroup;

6. Export

FData.Options.IO.Delimiter := ',';
FData.SaveToCSVData('output.csv');

7. Read typed values

Use typed accessors for performance in tight loops:

var Name  := FData.Strings[COL_NAME,  Row];
var Price := FData.Floats [COL_PRICE, Row];
var Stock := FData.Ints   [COL_STOCK, Row];

Connecting the headless layer to a visual grid

If you later want to display the processed data in a TTMSFNCDataGrid, you can copy it row by row or simply re-load the same source into the grid:

// Simplest: let the grid load its own copy
Grid.LoadFromJSONData(FileName, '', '', ['id', 'name', 'price']);

For a shared-source pattern, use TTMSFNCDataGridDatabaseAdapter against a common TDataSet. The data layer is best used for scenarios where you need data operations without any UI — for example, generating a filtered CSV in a background thread or computing statistics at startup.

  • TTMSFNCDataGridData
  • FData.LoadFromJSONData / LoadFromCSVData
  • FData.Filter.Add(AColumn, AFilterType, ACondition) — typed filter overload
  • FData.ApplyFilter / RemoveFilter
  • FData.IsRowDisplayed(ARow) — True if the row is visible after filter
  • FData.IsRowNode(ARow) — True if the row is a group header
  • FData.IsRowSummary(ARow) — True if the row is a group summary
  • FData.Sort(AColumn, ADirection)
  • FData.Group(AColumn) / Ungroup
  • FData.GroupSum / GroupCount / GroupAverage / GroupMin / GroupMax
  • FData.SaveToCSVData(AFileName) — delimiter set via Options.IO.Delimiter
  • FData.Strings[col, row] / Floats / Ints / Booleans — typed accessors
  • FData.FixedRowCount / ColumnCount / RowCount
  • FData.Options.IO.StartRow — set to 1 so JSON keys land in row 0 as headers

See also