An Angular wrapper library for AG Grid Community with an opinionated, production-ready feature set — including a translated toolbar, custom filters, master-detail rows, infinite scrolling, and a built-in language picker.
- Responsive Toolbar — title, row counter, action buttons (refresh, add, edit, delete), views, column manager, Excel export
- Column Manager — reorder, show/hide, pin, and rename columns; save/load named views via
localStorage - Custom Filters — set filter (contains + exact), number filter (=, >, ≥, <, ≤), date filter, text filter
- Filter Breadcrumbs — active filters shown as dismissible chips below the grid
- Master-Detail Rows — expandable rows with a detail panel (key-value chips); Community-edition compatible
- Infinite Scroll — AG Grid Infinite Row Model with server-side sort & filter support
- Localization — built-in 🇩🇪 German and 🇬🇧 English; all toolbar, filter panel, and pagination texts fully translated; extendable to any language
- Custom Pagination Bar — fully translated; replaces AG Grid's built-in panel
- Excel Export — visible + filtered rows only, via SheetJS (
.xlsx) - Loading Overlay — spinner with configurable text
- Cell Context Menu — copy value, set as filter, pin/unpin column
npm install nitgridPeer dependencies (install separately if not already present):
npm install ag-grid-community ag-grid-angular xlsximport { Component } from "@angular/core";
import { ColDef } from "ag-grid-community";
import { NITGridComponent } from "nitgrid";
@Component({
standalone: true,
imports: [NITGridComponent],
template: ` <nit-nitgrid title="Fahrzeuge" [columnDefs]="columnDefs" [rowData]="rowData" [excelExport]="true" rowSelection="multiple" height="60vh" /> `,
})
export class MyComponent {
columnDefs: ColDef[] = [
{ field: "make", headerName: "Marke" },
{ field: "model", headerName: "Modell" },
{ field: "price", headerName: "Preis", type: "numericColumn" },
];
rowData = [
{ make: "Toyota", model: "Celica", price: 35000 },
{ make: "Ford", model: "Mondeo", price: 32000 },
];
}| Input | Type | Default | Description |
|---|---|---|---|
rowData |
any[] |
[] |
Row data (client-side mode) |
columnDefs |
ColDef[] |
[] |
AG Grid column definitions |
gridOptions |
GridOptions |
{} |
Additional AG Grid options |
defaultColDef |
Partial<ColDef> |
sortable + filter + resizable | Default column settings |
title |
string |
'' |
Grid title shown in toolbar |
gridName |
string |
'' |
Key for saved views in localStorage |
userName |
string |
'' |
User key for saved views |
height |
string |
'500px' |
Grid height |
width |
string |
'100%' |
Grid width |
theme |
Theme |
themeQuartz |
AG Grid theme |
rowSelection |
'single' | 'multiple' |
— | Row selection mode |
pagination |
boolean |
false |
Enable pagination |
paginationPageSize |
number |
20 |
Rows per page |
loading |
boolean |
false |
Show loading overlay |
loadingText |
string |
'' |
Override loading text (falls back to locale) |
excelExport |
boolean |
false |
Show Excel Export button |
columnAutoFit |
boolean |
false |
Show Column Width button |
showBreadcrumbs |
boolean |
true |
Show active filter chips |
displayViews |
boolean |
false |
Show Views / Save View buttons |
masterDetail |
boolean |
false |
Enable expandable detail rows |
detailField |
string |
'details' |
Row field with { label, value }[] for detail panel |
detailRowHeight |
number |
120 |
Height of the detail panel in px |
rowModelType |
'clientSide' | 'infinite' |
'clientSide' |
AG Grid row model |
datasource |
IDatasource |
— | Datasource for infinite row model |
cacheBlockSize |
number |
100 |
Block size for infinite row model |
languages |
NITLanguage[] |
[] |
Language options for the built-in language picker |
| Output | Type | Description |
|---|---|---|
gridReady |
GridApi |
Fired when the grid is initialized |
rowClicked |
RowClickedEvent |
Row click |
rowSelected |
RowSelectedEvent |
Row selection change |
selectionChanged |
SelectionChangedEvent |
Selection changed |
filterChanged |
Record<string, any> |
Active filter model |
cellValueChanged |
NITCellValueChangedEvent |
Inline cell edit |
refresh |
void |
Refresh button clicked |
addRow |
void |
Add button clicked |
editRow |
any |
Edit confirmed (returns updated row) |
deleteRow |
any[] |
Delete confirmed (returns selected rows) |
languageChanged |
string |
Language code after switch (e.g. 'de', 'en') |
NITGrid ships with complete built-in translations for 14 languages. Every visible text is covered: toolbar buttons, dialogs, filter panels, breadcrumbs, pagination bar, and all AG Grid-internal texts (filter operators, column menu, pagination labels).
| Code | Language | Code | Language |
|---|---|---|---|
de |
🇩🇪 Deutsch | pl |
🇵🇱 Polski |
en |
🇬🇧 English | cs |
🇨🇿 Čeština |
fr |
🇫🇷 Français | hu |
🇭🇺 Magyar |
es |
🇪🇸 Español | ro |
🇷🇴 Română |
it |
🇮🇹 Italiano | sk |
🇸🇰 Slovenčina |
pt |
🇵🇹 Português | hr |
🇭🇷 Hrvatski |
nl |
🇳🇱 Nederlands | sl |
🇸🇮 Slovenščina |
Pass any subset of the built-in codes. Only the languages you list appear in the picker.
import { NITLanguage } from 'nitgrid';
// All 14 built-in languages:
languages: NITLanguage[] = [
{ code: 'de', label: 'Deutsch' },
{ code: 'en', label: 'English' },
{ code: 'fr', label: 'Français' },
{ code: 'es', label: 'Español' },
{ code: 'it', label: 'Italiano' },
{ code: 'pt', label: 'Português' },
{ code: 'nl', label: 'Nederlands' },
{ code: 'pl', label: 'Polski' },
{ code: 'cs', label: 'Čeština' },
{ code: 'hu', label: 'Magyar' },
{ code: 'ro', label: 'Română' },
{ code: 'sk', label: 'Slovenčina' },
{ code: 'hr', label: 'Hrvatski' },
{ code: 'sl', label: 'Slovenščina' },
];<nit-nitgrid [languages]="languages" defaultLanguage="de" [persistLanguage]="true" gridName="myGrid" (languageChanged)="onLangChange($event)" />| Option | Effect |
|---|---|
[languages] |
List of languages to show in the picker |
defaultLanguage |
Code of the language selected on first load (e.g. 'de') |
[persistLanguage]="true" |
Saves and restores the user's choice via localStorage (key: nit_lang_<gridName>) |
(languageChanged) |
Emits the selected language code whenever the user switches |
The first entry in the array is pre-selected if defaultLanguage is not set and no persisted preference exists. The language picker appears as a globe 🌐 icon to the left of the grid title.
For a language not in the built-in list, provide a nitText object with keys from NITToolbarTexts and optionally AG Grid's localeText keys. Use i18n/de.json as a key reference.
{ code: 'ja', label: '日本語',
nitText: {
refresh: '更新', add: '追加', edit: '編集', delete: '削除',
entries: '件', of: '/', pagerPage: 'ページ', /* … all NITToolbarTexts keys */
},
localeText: {
page: 'ページ', of: '/', noRowsToShow: 'データなし', /* AG Grid keys … */
},
}Expandable rows with a detail panel — Community-edition compatible (no Enterprise license required).
rowData = [
{
make: "Toyota",
model: "Celica",
price: 35000,
details: [
{ label: "Farbe", value: "Rot" },
{ label: "Antrieb", value: "Hinterrad" },
{ label: "Vorbesitzer", value: 1 },
],
},
];<nit-nitgrid [masterDetail]="true" detailField="details" [detailRowHeight]="110" [rowData]="rowData" [columnDefs]="columnDefs" />Use the IDatasource pattern for large datasets. AG Grid loads data in blocks and only renders what is visible.
import { IDatasource, IGetRowsParams } from "ag-grid-community";
datasource: IDatasource = {
getRows: (params: IGetRowsParams) => {
fetch("/api/rows", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
startRow: params.startRow,
endRow: params.endRow,
sortModel: params.sortModel,
filterModel: params.filterModel,
}),
})
.then((r) => r.json())
.then((d) => params.successCallback(d.rows, d.totalCount))
.catch(() => params.failCallback());
},
};<nit-nitgrid [rowModelType]="'infinite'" [datasource]="datasource" [cacheBlockSize]="100" [columnDefs]="columnDefs" />// DTOs
public record GridRowsRequest(
int StartRow, int EndRow,
List<SortModel>? SortModel,
Dictionary<string, FilterModel>? FilterModel);
public record SortModel(string ColId, string Sort);
public record FilterModel(
string FilterType, string? Type, string? Filter,
double? FilterFrom, double? FilterTo);
public record GridRowsResponse<T>(IEnumerable<T> Rows, int TotalCount);
// Minimal API endpoint
app.MapPost("/api/rows", async (GridRowsRequest req, AppDbContext db) =>
{
var query = db.Items.AsQueryable();
// Apply filters (WHERE)
if (req.FilterModel != null)
foreach (var (field, f) in req.FilterModel)
query = ApplyFilter(query, field, f);
// Apply sort (ORDER BY)
if (req.SortModel is { Count: > 0 })
query = ApplySort(query, req.SortModel[0]);
else
query = query.OrderBy(x => x.Id);
// Paginate (OFFSET / FETCH NEXT)
var total = await query.CountAsync();
var rows = await query.Skip(req.StartRow)
.Take(req.EndRow - req.StartRow)
.ToListAsync();
return Results.Ok(new GridRowsResponse<Item>(rows, total));
});- Bugs & feature requests: GitHub Issues
- Questions & ideas: GitHub Discussions
MIT — see LICENSE for details.