Editing
Five edit modes over the same grid. Batch collects changes (dirty markers, strike-through deletes) until Save changes; form replaces the row with an inline labeled form; the other modes write back immediately. First Name is required; Department uses a custom *ogeEditTemplate. Deleting asks for confirmation (confirmDelete).
editing required ogeEditTemplate savingChanges
editing: batch 30 rows
savingChanges log
- No saves yet
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { OgeColumn, OgeEditTemplate, OgeGrid } from '@oge-ui/grid';
import type { OgeSavingChangesEvent } from '@oge-ui/grid';
interface Employee {
id: number;
firstName: string;
department: string;
}
@Component({
selector: 'demo-root',
imports: [ReactiveFormsModule, OgeColumn, OgeEditTemplate, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="employees" keyField="id"
[editing]="{ mode: 'batch', allowUpdating: true, allowAdding: true, allowDeleting: true }"
(savingChanges)="onSaving($event)">
<oge-column field="id" [editable]="false" />
<oge-column field="firstName" [required]="true" />
<oge-column field="department">
<!-- custom editor gets the reactive FormControl -->
<select *ogeEditTemplate="let control" [formControl]="control">
<option>Engineering</option><option>Sales</option>
</select>
</oge-column>
</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 onSaving(event: OgeSavingChangesEvent<Employee>): void {
// event.changes = [{ type: 'update' | 'insert' | 'remove', key, data }]
// set event.cancel = true to abort; otherwise the DataSource
// (insert/update/remove) is called and the grid reloads.
console.log(event.changes);
}
}Cascading lookups & command-column customization
A lookup's dataSource may be a function of the row: while editing, it receives the draft values, so picking a country immediately re-filters the city editor. The command column is customizable through commandButtons — built-in edit/delete plus your own buttons with per-row visibility.
lookup cascading commandButtons
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid } from '@oge-ui/grid';
import type { OgeCommandButton } from '@oge-ui/grid';
interface Assignment {
id: number;
countryId: number;
cityId: number;
done: boolean;
}
const CITIES = [
{ id: 1, countryId: 1, name: 'Hamburg' },
{ id: 2, countryId: 1, name: 'Berlin' },
{ id: 3, countryId: 2, name: 'İzmir' },
];
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="assignments" keyField="id"
[editing]="{ mode: 'row', allowUpdating: true, allowDeleting: true }"
[commandButtons]="commandButtons">
<oge-column field="countryId" caption="Country"
[lookup]="{ dataSource: countries, valueExpr: 'id', displayExpr: 'name' }" />
<!-- cascading: the city list depends on the row's (draft) country -->
<oge-column field="cityId" caption="City"
[lookup]="{ dataSource: citiesOf, valueExpr: 'id', displayExpr: 'name' }" />
</oge-grid>
`,
})
export class Demo {
protected readonly assignments: Assignment[] = [
{ id: 1, countryId: 1, cityId: 1, done: false },
{ id: 2, countryId: 2, cityId: 3, done: true },
];
protected readonly countries = [
{ id: 1, name: 'Germany' },
{ id: 2, name: 'Türkiye' },
];
protected readonly citiesOf = (row: Assignment) =>
CITIES.filter((c) => c.countryId === row.countryId);
protected readonly commandButtons: OgeCommandButton<Assignment>[] = [
{ name: 'edit' },
{ name: 'delete' },
{
text: 'Archive',
visible: (row) => !row.done,
onClick: (row) => this.archive(row),
},
];
private archive(row: Assignment): void {
console.log('archive', row.id);
}
}Notes
- cell: click a cell (or press Enter/F2 on a focused one), edit, commit with Enter; Tab commits and moves to the next editable cell, Esc reverts.
- row / popup / form: use the command column's pencil button — all editable cells, a dialog, or an inline labeled form open at once with Save/Cancel.
confirmDelete: trueasks before a non-batch delete.editing.formItemspicks the fields (and their order, labels andcolSpan) that the form and popup editors show;formColCountfixes the layout column count.- batch: nothing touches the DataSource until Save changes; dirty cells get a corner marker, deletions a strike-through, and everything is sent as one ordered change set.
- Validation blocks commits:
[required]or any Angular[validators]mark the editor red and keep it open. - The same flow drives remote sources — implement
insert/update/removeon your DataSource.