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:

uses
  System.SysUtils, FMX.TMSFNCDataGridData;

procedure TMyForm.LoadRecords;
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:

uses
  FMX.TMSFNCDataGridData;

procedure TMyForm.LoadData(const FileName: string);
begin
  // 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;
end;

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

3. Filter

uses
  System.SysUtils, FMX.TMSFNCDataGridData;

procedure TMyForm.FilterData;
var
  R, Count: Integer;
begin
  FData.Filter.Clear;
  FData.Filter.Add(COL_CATEGORY, gftEqual, 'Meat');
  FData.ApplyFilter;

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

  // Remove all filters and show every row again
  FData.RemoveFilter;
end;

4. Sort

uses
  FMX.TMSFNCDataGridData;

procedure TMyForm.SortData;
begin
  FData.Sort(COL_PRICE, gsdDescending);
end;

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

5. Group with aggregations

uses
  System.SysUtils, FMX.TMSFNCDataGridData;

procedure TMyForm.GroupData;
var
  R: Integer;
begin
  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 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;
end;

6. Export

uses
  FMX.TMSFNCDataGridData;

procedure TMyForm.ExportData;
begin
  FData.Options.IO.Delimiter := ',';
  FData.SaveToCSVData('output.csv');
end;

7. Read typed values

Use typed accessors for performance in tight loops:

uses
  FMX.TMSFNCDataGridData;

procedure TMyForm.ReadTypedValues(Row: Integer);
var
  Name: string;
  Price: Double;
  Stock: Integer;
begin
  Name  := FData.Strings[COL_NAME,  Row];
  Price := FData.Floats [COL_PRICE, Row];
  Stock := FData.Ints   [COL_STOCK, Row];
end;

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:

uses
  FMX.TMSFNCDataGrid;

procedure TMyForm.ShowInGrid(const FileName: string);
begin
  Grid.LoadFromJSONData(FileName, '', '', ['id', 'name', 'price']);
end;

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