diff --git a/docs/data/routes/release-notes/en.md b/docs/data/routes/release-notes/en.md index e1f6899916..403c253d03 100644 --- a/docs/data/routes/release-notes/en.md +++ b/docs/data/routes/release-notes/en.md @@ -35,6 +35,7 @@ There are [migration instructions](/upgrade-guides/18.0) from JSS 16-based appli * [React-Native sample] Styleguide-ComponentParams fix incorrect `params` prop types in connected mode. * [React-Native sample] Fix connected tunnel mode for secure (https) Sitecore endpoints. * [PR #638](https://github.com/Sitecore/jss/pull/638) [sitecore-jss-nextjs] [samples/nextjs] Fix issue with `getStaticPaths`only pre-rendering the first 10 pages. +* [PR #677](https://github.com/Sitecore/jss/pull/677) [sitecore-jss-forms] Fix issue where pre-filled (default) form data isn't removed for multi-valued fields when user de-selects values. ## Sitecore JSS 16.0 for Sitecore 10.1 diff --git a/packages/sitecore-jss-forms/src/JssFormData.test.ts b/packages/sitecore-jss-forms/src/JssFormData.test.ts index 002cb8de59..abbb0dcc42 100644 --- a/packages/sitecore-jss-forms/src/JssFormData.test.ts +++ b/packages/sitecore-jss-forms/src/JssFormData.test.ts @@ -31,7 +31,19 @@ describe('JssFormData', () => { ]); }); - it('should merge overwriting existing values', () => { + it('should remove key', () => { + const formData = new JssFormData(); + + formData.append('xxx', 'val-xxx'); + formData.append('xxx', 'val-xxx'); + formData.append('yyy', 'val-yyy'); + + formData.remove('xxx'); + + expect(formData.get()).to.deep.equal([{ key: 'yyy', value: 'val-yyy' }]); + }); + + it('should merge overwriting existing empty data', () => { const x1formData = new JssFormData(); const x1 = { a1: 'a1-val', @@ -63,6 +75,49 @@ describe('JssFormData', () => { ]); }); + it('should merge overwriting existing pre-filled data', () => { + const x1formData = new JssFormData(); + x1formData.append('a1', 'a1-val1'); + x1formData.append('a2', 'a2-val1'); + const x1 = { + a1: 'a1-val2', + a2: 'a2-val2', + }; + + x1formData.mergeOverwritingExisting(x1); + + expect(x1formData.get()).to.deep.equal([ + { key: 'a1', value: 'a1-val2' }, + { key: 'a2', value: 'a2-val2' }, + ]); + + const x2formData = new JssFormData(); + x2formData.append('a1', 'a1-val1'); + x2formData.append('a3', 'a3-val1'); + x2formData.append('a5', 'a5-val1'); + x2formData.append('a5', 'a5-val2'); + + const x2 = { + a1: 'a1-val2', + a2: 'a2-val1', + a3: ['a3-val2', 'a3-val3'], + a4: ['a4-val1', 'a4-val2', 'a4-val3'], + a5: [], + }; + + x2formData.mergeOverwritingExisting(x2); + + expect(x2formData.get()).to.deep.equal([ + { key: 'a1', value: 'a1-val2' }, + { key: 'a2', value: 'a2-val1' }, + { key: 'a3', value: 'a3-val2' }, + { key: 'a3', value: 'a3-val3' }, + { key: 'a4', value: 'a4-val1' }, + { key: 'a4', value: 'a4-val2' }, + { key: 'a4', value: 'a4-val3' }, + ]); + }); + it('should convert data to url encoded form data', () => { const x1formData = new JssFormData(); diff --git a/packages/sitecore-jss-forms/src/JssFormData.ts b/packages/sitecore-jss-forms/src/JssFormData.ts index 89721da3b1..34b467e81f 100644 --- a/packages/sitecore-jss-forms/src/JssFormData.ts +++ b/packages/sitecore-jss-forms/src/JssFormData.ts @@ -21,10 +21,18 @@ export class JssFormData { * @param {string | File} value */ public set(key: string, value: string | File) { - this.data = this.data.filter((entry) => entry.key !== key); + this.remove(key); this.append(key, value); } + /** + * Removes any values for a given key from the form data. + * @param {string} key + */ + public remove(key: string) { + this.data = this.data.filter((entry) => entry.key !== key); + } + /** * Merges form data from a client-side state store (i.e. the user-specified values), overwriting any existing values for the keys * @param {Object} values @@ -38,13 +46,18 @@ export class JssFormData { // we want to _set_ the first one to override anything existing, // but _append_ anything after that to avoid overwriting our own values if (Array.isArray(value)) { - value.forEach((v: string | File, index: number) => { - if (index === 0) { - this.set(key, v); - } else { - this.append(key, v); - } - }); + if (value.length === 0) { + // if empty array, ensure any pre-filled values are cleared (i.e. user de-selected these) + this.remove(key); + } else { + value.forEach((v: string | File, index: number) => { + if (index === 0) { + this.set(key, v); + } else { + this.append(key, v); + } + }); + } } else { this.set(key, value.toString()); }