diff --git a/.changeset/large-apricots-kiss.md b/.changeset/large-apricots-kiss.md new file mode 100644 index 000000000..e128cdcfd --- /dev/null +++ b/.changeset/large-apricots-kiss.md @@ -0,0 +1,5 @@ +--- +'@lion/form-core': patch +--- + +Do a deep equals check for choice group children that have complex modelValues, enabling modelValue setter to work on the group level. diff --git a/packages/form-core/src/choice-group/ChoiceGroupMixin.js b/packages/form-core/src/choice-group/ChoiceGroupMixin.js index 98a6d1702..d609370de 100644 --- a/packages/form-core/src/choice-group/ChoiceGroupMixin.js +++ b/packages/form-core/src/choice-group/ChoiceGroupMixin.js @@ -44,7 +44,12 @@ const ChoiceGroupMixinImplementation = superclass => * @param {ChoiceInputHost} el * @param {any} val */ - const checkCondition = (el, val) => el.choiceValue === val; + const checkCondition = (el, val) => { + if (typeof el.choiceValue === 'object') { + return JSON.stringify(el.choiceValue) === JSON.stringify(value); + } + return el.choiceValue === val; + }; if (this.__isInitialModelValue) { this.__isInitialModelValue = false; @@ -281,7 +286,16 @@ const ChoiceGroupMixinImplementation = superclass => _setCheckedElements(value, check) { for (let i = 0; i < this.formElements.length; i += 1) { if (this.multipleChoice) { - this.formElements[i].checked = value.includes(this.formElements[i].value); + let valueIsIncluded = value.includes(this.formElements[i].modelValue.value); + + // For complex values, do a JSON Stringified includes check, because [{ v: 'foo'}].includes({ v: 'foo' }) => false + if (typeof this.formElements[i].modelValue.value === 'object') { + valueIsIncluded = /** @type {any[]} */ (value) + .map(/** @param {Object} v */ v => JSON.stringify(v)) + .includes(JSON.stringify(this.formElements[i].modelValue.value)); + } + + this.formElements[i].checked = valueIsIncluded; } else if (check(this.formElements[i], value)) { // Allows checking against custom values e.g. formattedValue or serializedValue this.formElements[i].checked = true; diff --git a/packages/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js b/packages/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js index a53ade6fe..5f0364c53 100644 --- a/packages/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +++ b/packages/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js @@ -286,7 +286,7 @@ export function runChoiceGroupMixinSuite({ parentTagString, childTagString, choi } }); - it('can check a radio by supplying an available modelValue', async () => { + it('can check a choice by supplying an available modelValue', async () => { const el = /** @type {ChoiceInputGroup} */ (await fixture(html` <${parentTag} name="gender[]"> <${childTag} @@ -310,6 +310,35 @@ export function runChoiceGroupMixinSuite({ parentTagString, childTagString, choi expect(el.formElements[2].checked).to.be.true; }); + it('can check a choice by supplying an available modelValue even if this modelValue is an array or object', async () => { + const el = /** @type {ChoiceInputGroup} */ (await fixture(html` + <${parentTag} name="gender[]"> + <${childTag} + .modelValue="${{ value: { v: 'male' }, checked: false }}" + > + <${childTag} + .modelValue="${{ value: { v: 'female' }, checked: true }}" + > + <${childTag} + .modelValue="${{ value: { v: 'other' }, checked: false }}" + > + + `)); + + if (cfg.choiceType === 'single') { + expect(el.modelValue).to.eql({ v: 'female' }); + } else { + expect(el.modelValue).to.deep.equal([{ v: 'female' }]); + } + + if (cfg.choiceType === 'single') { + el.modelValue = { v: 'other' }; + } else { + el.modelValue = [{ v: 'other' }]; + } + expect(el.formElements[2].checked).to.be.true; + }); + it('expect child nodes to only fire one model-value-changed event per instance', async () => { let counter = 0; const el = /** @type {ChoiceInputGroup} */ (await fixture(html`