saran456
(Saran456)
July 6, 2026, 11:15am
1
In cell type multiselect, when i click the X icon in chips, it not trigger AfterChange function why. Because I handle some condition and payload generation for save API inside the AfterChange function
hi @saran456 thanks for reporting this. I’ve created an issue here:
opened 12:45PM - 06 Jul 26 UTC
bug
## Summary
Removing a value from a `multiselect` cell by clicking the **X icon … on a rendered chip** updates the data but does **not** fire `beforeChange` / `afterChange`. Code that relies on `afterChange` (validation, dirty-tracking, save/persistence) silently misses these edits.
Removing the *same* value **via the editor** (open the dropdown → deselect) *does* fire `afterChange`, so the two removal paths are inconsistent.
Reported on the forum: https://forum.handsontable.com/t/cell-type-multiselect-x-icon-not-trigger-afterchange/9083
## Affected versions
17.x, **18.0.0**, and `develop` — identical code path. Not fixed by upgrading.
## Steps to reproduce
Minimal grid with a `multiselect` column and hooks on both `afterChange` and `afterSetSourceDataAtCell`:
```js
const hot = new Handsontable(el, {
data: [{ tags: ['Red', 'Green', 'Blue'] }],
columns: [{ data: 'tags', type: 'multiselect', source: ['Red', 'Green', 'Blue', 'Alpha'] }],
afterChange(changes, source) {
if (source !== 'loadData') console.log('afterChange', source, changes);
},
afterSetSourceDataAtCell(changes, source) {
console.log('afterSetSourceDataAtCell', source, changes);
},
licenseKey: 'non-commercial-and-evaluation',
});
```
1. The cell renders chips `Red`, `Green`, `Blue`.
2. Click the **X** icon on the `Red` chip.
### Observed
- The value is removed: `['Red','Green','Blue']` → `['Green','Blue']` ✔
- `afterChange` — **not fired** ✘
- `afterSetSourceDataAtCell` — fired, with `source: 'multiselect-renderer'`
Control: a normal `hot.setDataAtCell(...)` fires `afterChange` (`source: 'edit'`) as expected — so the hook is wired correctly and the chip path genuinely bypasses it.
### Expected
Clicking the chip X should fire the same hooks (and run validation) as any other cell edit — consistent with the editor's deselect path.
## Root cause
The rendered chip's remove handler (`registerChipRemovingEvents`) writes via `setSourceDataAtCell`, which bypasses the `beforeChange` / `afterChange` / validation pipeline —
`handsontable/src/renderers/multiSelectRenderer/utils/utils.ts:152` (same at `utils.js:151` in 17.1.0):
```ts
const newData = removeValueByKey(parseValue(currentData), keyToRemove);
hotInstance.setSourceDataAtCell(physicalRow, physicalColumn, newData, `${rendererType}-renderer`);
```
By contrast, the editor's removal path (`multiSelectEditor` `#removeSelectedValue` → `saveValue([[value]])`) routes through `setDataAtCell` and fires `afterChange`.
## Suggested fix
Route chip removal through `setDataAtCell` (or otherwise run the change/validation pipeline) instead of `setSourceDataAtCell`, so `beforeChange` / `afterChange` fire and the new value is validated — matching `saveValue` in the editor.
## Workaround (current releases)
Also listen to `afterSetSourceDataAtCell` and filter on `source === 'multiselect-renderer'`:
```js
afterSetSourceDataAtCell(changes, source) {
if (source !== 'multiselect-renderer') return;
changes.forEach(([row, prop, oldValue, newValue]) => {
// handle the chip removal with the same logic used in afterChange
});
}
```
I’ll update this thread as soon as I have an ETA on the fix. Thanks again!
1 Like
UPDATE : The fix is live on our dev branch.
We just released v18.0.0 last week so I’m not sure how long it will be for the next release. I’ll let you know as soon as I have an ETA.
1 Like