Skip to content

Commit

Permalink
[sitecore-jss-forms] Fix for multi-valued fields with pre-filled form…
Browse files Browse the repository at this point in the history
… data (#677)

* Fix issue where pre-filled (default) form data isn't removed for multi-valued fields when user de-selects values.
  • Loading branch information
ambrauer committed May 3, 2021
1 parent 5656712 commit da08c85
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 8 deletions.
134 changes: 134 additions & 0 deletions packages/sitecore-jss-forms/src/JssFormData.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { expect } from 'chai';

import { JssFormData } from './JssFormData';

describe('JssFormData', () => {
it('should append key/value', () => {
const formData = new JssFormData();

formData.append('xxx', 'val-xxx');
formData.append('xxx', 'val-xxx');
formData.append('yyy', 'val-yyy');

expect(formData.get()).to.deep.equal([
{ key: 'xxx', value: 'val-xxx' },
{ key: 'xxx', value: 'val-xxx' },
{ key: 'yyy', value: 'val-yyy' },
]);
});

it('should set key/value', () => {
const formData = new JssFormData();

formData.set('xxx', 'val-xxx');
formData.set('xxx', 'val-xxx');
formData.set('yyy', 'val-yyy');
formData.set('yyy', 'val-yyy');

expect(formData.get()).to.deep.equal([
{ key: 'xxx', value: 'val-xxx' },
{ key: 'yyy', value: 'val-yyy' },
]);
});

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',
a2: 'a2-val',
};

x1formData.mergeOverwritingExisting(x1);

expect(x1formData.get()).to.deep.equal([
{ key: 'a1', value: 'a1-val' },
{ key: 'a2', value: 'a2-val' },
]);

const x2formData = new JssFormData();
const x2 = {
x21: 'a1-val',
x22: 'a2-val',
x23: ['x231-arr-val', 'x232-arr-val', 'x233-arr-val'],
};

x2formData.mergeOverwritingExisting(x2);

expect(x2formData.get()).to.deep.equal([
{ key: 'x21', value: 'a1-val' },
{ key: 'x22', value: 'a2-val' },
{ key: 'x23', value: 'x231-arr-val' },
{ key: 'x23', value: 'x232-arr-val' },
{ key: 'x23', value: 'x233-arr-val' },
]);
});

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();

x1formData.append('x21', 'a1-val');
x1formData.append('x22', 'a2-val');
x1formData.append('x23', 'x231-arr-val');
x1formData.append('x23', 'x232-arr-val');
x1formData.append('x23', 'x233-arr-val');

expect(x1formData.toUrlEncodedFormData()).to.equal(
'x21=a1-val&x22=a2-val&x23=x231-arr-val&x23=x232-arr-val&x23=x233-arr-val'
);
});
});
29 changes: 21 additions & 8 deletions packages/sitecore-jss-forms/src/JssFormData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ export class JssFormData {

/** Sets a key/value, removing any existing value(s) set for that key. */
public set(key: string, value: string) {
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 */
public mergeOverwritingExisting(values: { [key: string]: string | string[] | boolean }) {
Object.keys(values).forEach((key) => {
Expand All @@ -27,13 +35,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, index) => {
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, index) => {
if (index === 0) {
this.set(key, v);
} else {
this.append(key, v);
}
});
}
} else {
this.set(key, value.toString());
}
Expand Down

0 comments on commit da08c85

Please sign in to comment.