Open pboguslawski opened 1 year ago
Related to https://github.com/hperrin/svelte-material-ui/issues/240, in which the select all checkbox becomes checked when a user selects an extraneous checkbox located within a data table.
Minimal reproduction: https://github.com/vhscom/smui-issue-562-repo-data-table-header-checkbox
Verified issue is not a clear regression by backing down from ^7.0.0-beta.0
to v6.2.0
and can reproduce.
I've created two workarounds, one using a Svelte key
block here:
https://github.com/vhscom/smui-issue-562-repo-data-table-header-checkbox/tree/key-block-workaround
And another workaround by controlling the state of the header checkbox manually: https://github.com/vhscom/smui-issue-562-repo-data-table-header-checkbox/tree/state-handling-workaround
Video of key
workaround in action attached (same effect as the state management workaround):
In reviewing the upstream MDC-Web component framework I did not see any related issues so I assume this a SMUI bug and the DataTable
component notifies of row selection change when bound collection mutated.
I have also discovered that removing items from the table while some are selected causes completely unpredictable (to me at least) behavior. I have a basic table with CRUD support, and removing rows completely breaks the selection. Also, as demonstrated in the above video, the rows stay in the selected state even after their checkbox has become unchecked. I peeked into the code and saw there's some weird state management going on and I can't pretend I understand it, but it's clearly not working properly. The most reliable workaround I've come up with is programmatically clicking the uppermost checkbox once or twice depending on how many elements were selected, as this completely propagates the events as intended.
This workaround I have just come up with solves all of these problems for now. I think it's very strange that we have to do this but oh well, it works:
<script lang="ts">
... (imports and such) ...
let mainCheckboxInst: Checkbox;
let boxes: {
[index: number]: Checkbox
} = {};
let selected = [];
const deselectAll = () => {
if (selected.length == 0) {
return;
}
if (selected.length != Object.keys(boxes).length) {
mainCheckboxInst.getElement().querySelector("input")!.click();
}
mainCheckboxInst.getElement().querySelector("input")!.click();
};
const deleteSelected = async () => {
const ids = selected.map((sel) => sel.id);
for (let id of ids) {
boxes[id].getElement().querySelector("input")!.click();
}
// ... actual fetch request or something here
options = options.filter((option) => !ids.includes(option.id));
deselectAll();
};
</script>
<DataTable stickyHeader>
<Head>
<Row>
<Cell checkbox><Checkbox bind:this={mainCheckboxInst} /></Cell>
<Cell>(option fields here)</Cell>
...
</Row>
</Head>
<Body>
{#each options as option}
<Row>
<Cell checkbox>
<Checkbox
bind:group={selected}
bind:this={boxes[option.id]}
value={option}
valueKey={''+option.id}
/>
</Cell>
<Cell>{... (option fields here) ...}</Cell>
...
</Row>
{/each}
</Body>
</DataTable>
The important parts here are: 1) make sure to click the header checkbox twice if we haven't selected every element, because the first click will select the rest 2) if you remove a field, BEFORE REMOVING IT, you must click the corresponding checkbox to remove it from the selections group, otherwise the entire thing falls to pieces and completely fails to manage the state properly from that point on
My takeaway from this is that the entire checkbox state management seems to be built upon click events and not state changes to the checked
prop, because that is abstracted one step away from the actual checkbox through some strange magic that goes way over my head. Before arriving here, I tried every combination of managing props manually, and literally nothing worked at all until I started sending click events to control the state. Hope this can be fixed soon because I think this is very inefficient.
Describe the bug DataTable header checkbox state is not updated after programmatically (un)checking items using selected array.
To Reproduce
Steps to reproduce the behavior:
Expected behavior Header checkbox should be unchecked if was checked or "-".
Similar problem when unchecking all using header checkbox and then pressing "Check all" or "Check some" link.
Desktop: