I'm having an issue with HandsOnTable in Angular where numeric cell values are not being displayed after editing, although the validation and edit events are triggering correctly. I recently migrated from Angular 4 to Angular 18 and switched from using the JS full import to using the HandsOnTable Angular component. Problem: When I edit a numerical cell, the new value is not shown in the table, even though: The validation triggers correctly BeforeChange event triggers correctly AfterChange event triggers correctly Component Setup: @Component({ selector: 'dlb-handsontable', templateUrl: './handsontable.component.html' }) export class HandsontableComponent implements AfterViewInit, OnChanges, OnDestroy { public hot!: Handsontable; @Input() set data(data: any) { this._data = data; if (this.hot) { this.updateData(data); this.sort(); setTimeout(() => { this.sort(this.sorting.column, this.sorting.order); this.render(); }, 200); } } // Key configuration for numeric cells public setupHandsontable(dataSchema: any = null) { this.container = this.el.nativeElement.querySelector('#hot-demo'); this.dataSchema = dataSchema; const hotSettings: Handsontable.GridSettings = { data: this._data, licenseKey: 'non-commercial-and-evaluation', colHeaders: this._colHeaders, columns: this._columns, columnSorting: {indicator: true}, minSpareRows: 0, fixedColumnsLeft: 2, manualColumnResize: true, afterChange: (changes: CellChange[] | null, source: ChangeSource) => { changes!.forEach(change => { if (change![2] === change![3]) return; const row = change![0]; const physicalIndex = this.hot.toPhysicalRow(row); const data: RowObject = this.hot.getSourceDataAtRow(physicalIndex); if (data) { console.log(data); } }) } beforeChange: (changes: (CellChange | null)[], source: ChangeSource) => { if (source === 'loadData' || !changes) { return; //don't do anything as this is called when table is loaded } changes.forEach(change => { if (change![2] === change![3]) return; const row = change![0]; const physicalIndex = this.hot.toPhysicalRow(row); const data: RowObject = this.hot.getSourceDataAtRow(physicalIndex); if (data) { data['setDirty'] = true; this._isChanged = true; } }); }, afterRender: () => { requestAnimationFrame(() => { this.processing.emit({isProcessing: false}); }); } }; this.hot = new Handsontable(this.container!, hotSettings); if (dataSchema) { this.updateSettings({ dataSchema: this.dataSchema }); } } } Column Definition: const numericColumns: NumericColumn[] = months.map((x) => ({ data: this.dateproperty(x.toDBDateString()), allowEmpty: true, format: '0,0.0', type: 'numeric', colWidths: 90, validator: this.allocationValidator, columnSorting: true, renderer: this.allocationRenderer, })); AllocationComponent (Parent): @Component({ selector: 'allocations', templateUrl: './allocations.component.html', }) export class AllocationsComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild(HandsontableComponent, { static: false }) handsontable?: HandsontableComponent; private generateColumns(): ColumnDefinition[] { // ... other columns const numericColumns: NumericColumn[] = months.map((x) => ({ data: this.dateproperty(x.toDBDateString()), allowEmpty: true, format: '0,0.0', type: 'numeric', colWidths: 90, validator: this.allocationValidator, columnSorting: true, renderer: this.allocationRenderer, })); return [...dynamicColumns, ...numericColumns]; } private customRenderer = ( instance: Handsontable.Core, TD: HTMLTableCellElement, row: number, column: number, prop: string | number, value: any, cellProperties: Handsontable.CellProperties, renderer: any ) => { Handsontable.renderers.NumericRenderer.call( this, instance, TD, row, column, prop, value, cellProperties ); const physicalIndex = instance.toPhysicalRow(row); const data: Handsontable.RowObject = instance.getSourceDataAtRow(physicalIndex); if (data) { TD.classList.remove('modified-cell', 'red-cell'); if (data["isDirty"] && cellProperties["isModified"]) { TD.classList.add('modified-cell'); } else if (data["isDirty"] && !data["isValid"]) { TD.classList.add('red-cell'); } } return TD; }; public allocationRenderer = (instance: any, td: any, row: any, col: any, prop: any, value: any, cellProperties: any) => { let renderer = Handsontable.renderers.NumericRenderer; this.customRenderer(instance, td, row, col, prop, value, cellProperties, renderer); }; private dateproperty(date: string) { return (row: any) => { if (!row?.allocations) return; const allocation = row.allocations.find( (alloc: any) => alloc.month === date ); return allocation ? allocation.alloc_percent : null; }; } } What I've tried: Verified that the data is being updated in the model through console logs Checked that the renderer is being called Confirmed that validation is working Added manual render() calls after updates Verified that dateproperty accessor is returning correct values Checked the customRenderer implementation Expected behavior: When editing a numeric cell, the new value should be displayed immediately in the table. Actual behavior: The cell appears empty or keeps the old value after editing, even though the underlying data has changed (confirmed through console.logs). Environment: Angular: 18 HandsOnTable version: latest Browser: Chrome 120 Any help would be appreciated in identifying why the numeric cell values aren't being displayed after editing. Continue reading...