Skip to content

Commit d341f7b

Browse files
committed
bug #1155 Handle array-like objects when working with checkboxes (Lustmored)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- Handle array-like objects when working with checkboxes | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Tickets | | License | MIT First of all please take a look at added test cases. I think it shows the purpose of this change clearly. Background: Recently when working with forms inside a component I ran into a corner case, where Symfony forms are setting a non-zero-indexed array for the properties of `ChoiceType` with both `multiple` and `expanded`. It breaks live-component model assumption that multiple checkboxes keep their value as an array, which in JavaScript is always zero-indexed. It happens after a pretty weird set of steps: - check any option (foo) - check any other option (bar) - check the third option (baz) - uncheck option 'foo' <- Symfony forms store current value as `[1 => 'bar', 2 => 'baz']` - uncheck option 'bar' <- at this point current implementation is treating checkboxes as a single value and send back `null` instead of `['baz']`. This simple change fixes this flow (tested on a real life project). I don't see any correlation with failing tests. Commits ------- 6b75580 Handle array-like objects when working with checkboxes
2 parents a760b37 + 6b75580 commit d341f7b

File tree

3 files changed

+12
-0
lines changed

3 files changed

+12
-0
lines changed

src/LiveComponent/assets/dist/live_controller.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ function getValueFromElement(element, valueStore) {
162162
if (Array.isArray(modelValue)) {
163163
return getMultipleCheckboxValue(element, modelValue);
164164
}
165+
else if (Object(modelValue) === modelValue) {
166+
return getMultipleCheckboxValue(element, Object.values(modelValue));
167+
}
165168
}
166169
if (element.hasAttribute('value')) {
167170
return element.checked ? element.getAttribute('value') : null;

src/LiveComponent/assets/src/dom_utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export function getValueFromElement(element: HTMLElement, valueStore: ValueStore
2020
const modelValue = valueStore.get(modelNameData.action);
2121
if (Array.isArray(modelValue)) {
2222
return getMultipleCheckboxValue(element, modelValue);
23+
} else if (Object(modelValue) === modelValue) {
24+
// we might get objects of values from forms, like {'1': 'foo', '2': 'bar'}
25+
// this occurs in symfony forms with expanded ChoiceType when first checked options get unchecked
26+
return getMultipleCheckboxValue(element, Object.values(modelValue));
2327
}
2428
}
2529

src/LiveComponent/assets/test/dom_utils.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ describe('getValueFromElement', () => {
3232

3333
expect(getValueFromElement(input, createStore({ foo: ['bar'] })))
3434
.toEqual(['bar', 'the_checkbox_value']);
35+
36+
expect(getValueFromElement(input, createStore({ foo: {'1': 'bar'} })))
37+
.toEqual(['bar', 'the_checkbox_value']);
3538
});
3639

3740
it('Correctly removes data from valued unchecked checkbox', () => {
@@ -50,6 +53,8 @@ describe('getValueFromElement', () => {
5053
.toEqual(['bar']);
5154
expect(getValueFromElement(input, createStore({ foo: ['bar', 'the_checkbox_value'] })))
5255
.toEqual(['bar']);
56+
expect(getValueFromElement(input, createStore({ foo: {'1': 'bar', '2': 'the_checkbox_value'} })))
57+
.toEqual(['bar']);
5358
});
5459

5560
it('Correctly handles boolean checkbox', () => {

0 commit comments

Comments
 (0)