Rows & Templates
Full control over row rendering: replace entire rows with *ogeRowTemplate, style the empty state with *ogeNoDataTemplate, reorder rows by dragging, track a focused row and show a loading panel while remote data is in flight.
ogeRowTemplate ogeNoDataTemplate rowDragging focusedRow loadPanel
ogeRowTemplate rowAlternation
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid, OgeRowTemplate } from '@oge-ui/grid';
interface Employee {
firstName: string;
lastName: string;
department: string;
city: string;
salary: number;
}
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid, OgeRowTemplate],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="employees" keyField="id" [rowAlternation]="true">
<oge-column field="firstName" caption="Employee" />
<oge-column field="department" caption="Department" />
<oge-column field="salary" caption="Salary" dataType="number" />
<!-- replaces the whole row; columns still drive header, sorting & filtering -->
<div *ogeRowTemplate="let employee; of: employees; index as i" class="flex items-center gap-3 px-3 py-2">
<span class="avatar">{{ initials(employee) }}</span>
<div>
<div>{{ employee.firstName }} {{ employee.lastName }}</div>
<div class="muted">{{ employee.department }} · {{ employee.city }}</div>
</div>
<span class="ml-auto">{{ money(employee.salary) }}</span>
</div>
</oge-grid>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
protected initials(employee: Employee): string {
return `${employee.firstName[0]}${employee.lastName[0]}`;
}
protected money(value: number): string {
return value.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' });
}
}Row drag & drop + focused row
rowDragging focusedRowEnabled
Focused row key: —
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { OgeColumn, OgeGrid } from '@oge-ui/grid';
import type { RowKey } from '@oge-ui/core';
import type { OgeRowReorderedEvent } from '@oge-ui/grid';
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="employees" keyField="id"
[rowDragging]="true" (rowReordered)="onReordered($event)"
[focusedRowEnabled]="true" [(focusedRowKey)]="focusedKey">
<oge-column field="firstName" />
</oge-grid>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
protected readonly focusedKey = signal<RowKey | null>(null);
protected onReordered(event: OgeRowReorderedEvent<unknown>): void {
console.log(event.fromIndex, '→', event.toIndex);
}
}Empty state & loading panel
ogeNoDataTemplate loadPanel 800ms latency
Loading…
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid, OgeNoDataTemplate } from '@oge-ui/grid';
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid, OgeNoDataTemplate],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="employees" keyField="id" [loadPanel]="true">
<oge-column field="firstName" />
<div *ogeNoDataTemplate class="empty-state">
No employees match — adjust the filter or add a new record.
</div>
</oge-grid>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
}Notes
*ogeRowTemplatereplaces only data rows — group rows, detail rows and summaries keep their built-in rendering; sorting/filtering/selection still work through the declared columns.rowAlternationstripes odd rows via the--oge-row-alt-bgtoken.rowReorderedreports the moved key plus from/to view positions; with a plain array the order is persisted in place.focusedRowKeyis a two-way model — set it programmatically and the row highlights (and vice versa).loadPanelshows a spinner overlay for any in-flight load of a remote source.