GridLazyForm
Directive that provides lazy FormGroup creation for grid editing.
Unlike GridFormArray which creates all FormGroups upfront, this directive
creates FormGroups on-demand only when a row enters edit mode. This provides
much better performance for large datasets while still enabling full
Angular Reactive Forms integration.
Key Benefits
Section titled “Key Benefits”- Performance: Only creates FormGroups for rows being edited (20-100x fewer controls)
- Same DX: Editors still receive
controlin their context for validation - Memory efficient: FormGroups are cleaned up when rows exit edit mode
import { Component, inject, signal } from '@angular/core';import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';import { Grid, GridLazyForm, TbwEditor } from '@toolbox-web/grid-angular';
@Component({ imports: [Grid, GridLazyForm, TbwEditor, ReactiveFormsModule], template: ` <tbw-grid [rows]="employees()" [lazyForm]="createRowForm" [gridConfig]="config">
<tbw-grid-column field="firstName"> <input *tbwEditor="let _; control as ctrl" [formControl]="ctrl" [class.is-invalid]="ctrl?.invalid && ctrl?.touched" /> </tbw-grid-column> </tbw-grid> `})export class MyComponent { private fb = inject(FormBuilder); employees = signal(generateEmployees(1000));
// Factory called when editing starts - only include editable fields! createRowForm = (row: Employee): FormGroup => this.fb.group({ firstName: [row.firstName, Validators.required], lastName: [row.lastName, Validators.minLength(2)], salary: [row.salary, [Validators.required, Validators.min(0)]], });
gridConfig = { columns: [...] };}How It Works
Section titled “How It Works”- Rows come from
[rows]input (plain data array) - When a cell enters edit mode, the FormGroup is created lazily
- Editors receive the FormControl in their template context
- On commit, FormGroup values are synced back to the row
- FormGroup is cleaned up when the row exits edit mode (configurable)
Performance Comparison
Section titled “Performance Comparison”| Rows | GridFormArray (20 fields) | GridLazyForm |
|---|---|---|
| 100 | 2,000 controls | ~20 controls |
| 500 | 10,000 controls | ~20 controls |
| 1000 | 20,000 controls | ~20 controls |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
lazyForm | InputSignal<LazyFormFactory<TRow>> | Factory function to create a FormGroup for a row. Called lazily when the row first enters edit mode. |
syncValidation | InputSignal<boolean> | Whether to automatically sync Angular validation state to grid’s visual invalid styling. |
keepFormGroups | InputSignal<boolean> | Whether to keep FormGroups cached after a row exits edit mode. |
rowFormChange | OutputEmitterRef<RowFormChangeEvent<TRow>> | Emitted when a row’s form values change. Useful for auto-save, validation display, or syncing to external state. |
Property Details
Section titled “Property Details”lazyForm
Section titled “lazyForm”createRowForm = (row: Employee): FormGroup => this.fb.group({ firstName: [row.firstName, Validators.required], lastName: [row.lastName], salary: [row.salary, [Validators.min(0)]],});syncValidation
Section titled “syncValidation”Whether to automatically sync Angular validation state to grid’s visual invalid styling.
When enabled:
- After a cell commit, if the FormControl is invalid, the cell is marked with
setInvalid() - When a FormControl becomes valid,
clearInvalid()is called - On
row-commit, if the row’s FormGroup has invalid controls, the commit is prevented
Default: true
keepFormGroups
Section titled “keepFormGroups”Whether to keep FormGroups cached after a row exits edit mode.
true: FormGroups are kept, preserving dirty/touched state across edit sessionsfalse: FormGroups are disposed when the row exits edit mode (default)
Default: false
Methods
Section titled “Methods”ngOnInit()
Section titled “ngOnInit()”A callback method that is invoked immediately after the default change detector has checked the directive’s data-bound properties for the first time, and before any of the view or content children have been checked. It is invoked only once when the directive is instantiated.
ngOnInit(): voidngOnDestroy()
Section titled “ngOnDestroy()”A callback method that performs custom clean-up, invoked immediately before a directive, pipe, or service instance is destroyed.
ngOnDestroy(): voidgetFormGroup()
Section titled “getFormGroup()”Gets the FormGroup for a row, if it exists. Unlike the context methods, this does NOT create a FormGroup lazily.
getFormGroup(rowIndex: number): FormGroup<any> | undefinedParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
rowIndex | number | The row index |
Returns
Section titled “Returns”FormGroup<any> | undefined - The FormGroup or undefined
getAllFormGroups()
Section titled “getAllFormGroups()”Gets all cached FormGroups. Useful for bulk validation or inspection.
getAllFormGroups(): ReadonlyMap<TRow, FormGroup<any>>Returns
Section titled “Returns”ReadonlyMap<TRow, FormGroup<any>> - Map of row objects to their FormGroups
clearAllFormGroups()
Section titled “clearAllFormGroups()”Clears all cached FormGroups. Useful when the underlying data changes significantly.
clearAllFormGroups(): voidvalidateAll()
Section titled “validateAll()”Validates all currently cached FormGroups.
validateAll(): booleanReturns
Section titled “Returns”boolean - true if all FormGroups are valid, false otherwise