fix(fieldset): reset / inital modelValue always accurate
This commit is contained in:
parent
995e8f99de
commit
085895ee94
2 changed files with 181 additions and 117 deletions
|
|
@ -11,7 +11,7 @@ const pascalCase = str => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
/**
|
/**
|
||||||
* LionFieldset: fieldset wrapper providing extra features and integration with lion-field elements.
|
* LionFieldset: fieldset wrapper providing extra features and integration with lion-field elements.
|
||||||
*
|
*
|
||||||
* @customElement
|
* @customElement lion-fieldset
|
||||||
* @extends LionLitElement
|
* @extends LionLitElement
|
||||||
*/
|
*/
|
||||||
export class LionFieldset extends FormRegistrarMixin(
|
export class LionFieldset extends FormRegistrarMixin(
|
||||||
|
|
@ -176,7 +176,14 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
resetGroup() {
|
resetGroup() {
|
||||||
this.modelValue = this.resetModelValue;
|
this.formElementsArray.forEach(child => {
|
||||||
|
if (typeof child.resetGroup === 'function') {
|
||||||
|
child.resetGroup();
|
||||||
|
} else if (typeof child.reset === 'function') {
|
||||||
|
child.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.resetInteractionState();
|
this.resetInteractionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +252,7 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get's triggered by event 'validatin-done' which enabled us to handle 2 different situations
|
* Gets triggered by event 'validation-done' which enabled us to handle 2 different situations
|
||||||
* - react on modelValue change, which says something about the validity as a whole
|
* - react on modelValue change, which says something about the validity as a whole
|
||||||
* (at least two checkboxes for instance) and nothing about the children's values
|
* (at least two checkboxes for instance) and nothing about the children's values
|
||||||
* - children validatity states have changed, so fieldset needs to update itself based on that
|
* - children validatity states have changed, so fieldset needs to update itself based on that
|
||||||
|
|
@ -348,23 +355,16 @@ export class LionFieldset extends FormRegistrarMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the resetModelValue of this fieldset and asks it's parent fieldset/group to also
|
* Gathers initial model values of all children. Used
|
||||||
* update.
|
* when resetGroup() is called.
|
||||||
* This is needed as the upgrade order is not guaranteed. We have 3 main cases:
|
|
||||||
* 1. if `street-name` gets updated last then `address` and `details` needs to update their
|
|
||||||
* resetModelValue to also incorporate the correct value of `street-name`/`address`.
|
|
||||||
* 2. If `address` get updated last then it already has the correct `street-name` so it
|
|
||||||
* requests an update only for `details`.
|
|
||||||
* 3. If `details` get updated last nothing happens here as all data are up to date
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <lion-fieldset name="details">
|
|
||||||
* <lion-fieldset name="address">
|
|
||||||
* <lion-input name="street-name" .modelValue=${'street 1'}>
|
|
||||||
*/
|
*/
|
||||||
_updateResetModelValue() {
|
get _initialModelValue() {
|
||||||
this.resetModelValue = this.modelValue;
|
return this._getFromAllFormElements('_initialModelValue');
|
||||||
this._requestParentFormGroupUpdateOfResetModelValue();
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
|
get resetModelValue() {
|
||||||
|
return this._initialModelValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import '../lion-fieldset.js';
|
||||||
|
|
||||||
const tagString = 'lion-fieldset';
|
const tagString = 'lion-fieldset';
|
||||||
const tag = unsafeStatic(tagString);
|
const tag = unsafeStatic(tagString);
|
||||||
const inputSlotString = `
|
const childTagString = 'lion-input';
|
||||||
<lion-input name="gender[]"></lion-input>
|
const childTag = unsafeStatic(childTagString);
|
||||||
<lion-input name="gender[]"></lion-input>
|
const inputSlots = html`
|
||||||
<lion-input name="color"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="color"></${childTag}>
|
||||||
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
`;
|
`;
|
||||||
const nonPrefilledModelValue = '';
|
const nonPrefilledModelValue = '';
|
||||||
const prefilledModelValue = 'prefill';
|
const prefilledModelValue = 'prefill';
|
||||||
|
|
@ -30,7 +32,7 @@ beforeEach(() => {
|
||||||
|
|
||||||
describe('<lion-fieldset>', () => {
|
describe('<lion-fieldset>', () => {
|
||||||
it(`${tagString} has an up to date list of every form element in #formElements`, async () => {
|
it(`${tagString} has an up to date list of every form element in #formElements`, async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
||||||
expect(fieldset.formElements['hobbies[]'].length).to.equal(2);
|
expect(fieldset.formElements['hobbies[]'].length).to.equal(2);
|
||||||
|
|
@ -40,12 +42,12 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`supports in html wrapped form elements`, async () => {
|
it(`supports in html wrapped form elements`, async () => {
|
||||||
const el = await fixture(`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<div>
|
<div>
|
||||||
<lion-input name="foo"></lion-input>
|
<${childTag} name="foo"></${childTag}>
|
||||||
</div>
|
</div>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.formElementsArray.length).to.equal(1);
|
expect(el.formElementsArray.length).to.equal(1);
|
||||||
|
|
@ -54,7 +56,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles names with ending [] as an array', async () => {
|
it('handles names with ending [] as an array', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['gender[]'][0].modelValue = { value: 'male' };
|
fieldset.formElements['gender[]'][0].modelValue = { value: 'male' };
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
|
|
@ -75,7 +77,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset></lion-fieldset>`);
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -94,7 +96,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset name="foo"></lion-fieldset>`);
|
const el = await fixture(html`<${tag} name="foo"></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -113,7 +115,7 @@ describe('<lion-fieldset>', () => {
|
||||||
console.info = () => {};
|
console.info = () => {};
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
const el = await fixture(`<lion-fieldset></lion-fieldset>`);
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
try {
|
try {
|
||||||
// we test the api directly as errors thrown from a web component are in a
|
// we test the api directly as errors thrown from a web component are in a
|
||||||
// different context and we can not catch them here => register fake elements
|
// different context and we can not catch them here => register fake elements
|
||||||
|
|
@ -132,8 +134,8 @@ describe('<lion-fieldset>', () => {
|
||||||
/* eslint-enable no-console */
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
it('can dynamically add/remove elements', async () => {
|
it('can dynamically add/remove elements', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
const newField = await fixture(`<lion-input name="lastName"></lion-input>`);
|
const newField = await fixture(html`<${childTag} name="lastName"></${childTag}>`);
|
||||||
|
|
||||||
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
expect(Object.keys(fieldset.formElements).length).to.equal(3);
|
||||||
|
|
||||||
|
|
@ -145,11 +147,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can read/write all values (of every input) via this.modelValue', async () => {
|
it('can read/write all values (of every input) via this.modelValue', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="lastName"></lion-input>
|
<${childTag} name="lastName"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await fieldset.registrationReady;
|
await fieldset.registrationReady;
|
||||||
const newFieldset = fieldset.querySelector('lion-fieldset');
|
const newFieldset = fieldset.querySelector('lion-fieldset');
|
||||||
|
|
@ -190,10 +192,10 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('does not throw if setter data of this.modelValue can not be handled', async () => {
|
it('does not throw if setter data of this.modelValue can not be handled', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="firstName" .modelValue=${'foo'}></lion-input>
|
<${childTag} name="firstName" .modelValue=${'foo'}></${childTag}>
|
||||||
<lion-input name="lastName" .modelValue=${'bar'}></lion-input>
|
<${childTag} name="lastName" .modelValue=${'bar'}></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const initState = {
|
const initState = {
|
||||||
|
|
@ -210,7 +212,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables/enables all its formElements if it becomes disabled/enabled', async () => {
|
it('disables/enables all its formElements if it becomes disabled/enabled', async () => {
|
||||||
const el = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} disabled>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.formElements.color.disabled).to.equal(true);
|
expect(el.formElements.color.disabled).to.equal(true);
|
||||||
expect(el.formElements['hobbies[]'][0].disabled).to.equal(true);
|
expect(el.formElements['hobbies[]'][0].disabled).to.equal(true);
|
||||||
|
|
@ -225,7 +227,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('does not propagate/override initial disabled value on nested form elements', async () => {
|
it('does not propagate/override initial disabled value on nested form elements', async () => {
|
||||||
const el = await fixture(
|
const el = await fixture(
|
||||||
`<${tagString}><${tagString} name="sub" disabled>${inputSlotString}</${tagString}></${tagString}>`,
|
html`<${tag}><${tag} name="sub" disabled>${inputSlots}</${tag}></${tag}>`,
|
||||||
);
|
);
|
||||||
await el.updateComplete;
|
await el.updateComplete;
|
||||||
expect(el.disabled).to.equal(false);
|
expect(el.disabled).to.equal(false);
|
||||||
|
|
@ -237,7 +239,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
// classes are added only for backward compatibility - they are deprecated
|
// classes are added only for backward compatibility - they are deprecated
|
||||||
it('sets a state-disabled class when disabled', async () => {
|
it('sets a state-disabled class when disabled', async () => {
|
||||||
const el = await fixture(`<${tagString} disabled>${inputSlotString}</${tagString}>`);
|
const el = await fixture(html`<${tag} disabled>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(el.classList.contains('state-disabled')).to.equal(true);
|
expect(el.classList.contains('state-disabled')).to.equal(true);
|
||||||
el.disabled = false;
|
el.disabled = false;
|
||||||
|
|
@ -252,10 +254,10 @@ describe('<lion-fieldset>', () => {
|
||||||
}
|
}
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="color"
|
<${childTag} name="color"
|
||||||
.errorValidators=${[[isCat]]}
|
.errorValidators=${[[isCat]]}
|
||||||
.modelValue=${'blue'}
|
.modelValue=${'blue'}
|
||||||
></lion-input>
|
></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -263,7 +265,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('validates when a value changes', async () => {
|
it('validates when a value changes', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const spy = sinon.spy(fieldset, 'validate');
|
const spy = sinon.spy(fieldset, 'validate');
|
||||||
fieldset.formElements.color.modelValue = { checked: true, value: 'red' };
|
fieldset.formElements.color.modelValue = { checked: true, value: 'red' };
|
||||||
|
|
@ -277,10 +279,10 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="color"
|
<${childTag} name="color"
|
||||||
.errorValidators=${[[isCat]]}
|
.errorValidators=${[[isCat]]}
|
||||||
.modelValue=${'blue'}
|
.modelValue=${'blue'}
|
||||||
></lion-input>
|
></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -297,12 +299,12 @@ describe('<lion-fieldset>', () => {
|
||||||
}
|
}
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag} .errorValidators=${[[hasEvenNumberOfChildren]]}>
|
<${tag} .errorValidators=${[[hasEvenNumberOfChildren]]}>
|
||||||
<lion-input id="c1" name="c1"></lion-input>
|
<${childTag} id="c1" name="c1"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
const child2 = await fixture(
|
const child2 = await fixture(
|
||||||
html`
|
html`
|
||||||
<lion-input name="c2"></lion-input>
|
<${childTag} name="c2"></${childTag}>
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -326,7 +328,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
describe('interaction states', () => {
|
describe('interaction states', () => {
|
||||||
it('has false states (dirty, touched, prefilled) on init', async () => {
|
it('has false states (dirty, touched, prefilled) on init', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
expect(fieldset.dirty).to.equal(false, 'dirty');
|
expect(fieldset.dirty).to.equal(false, 'dirty');
|
||||||
expect(fieldset.touched).to.equal(false, 'touched');
|
expect(fieldset.touched).to.equal(false, 'touched');
|
||||||
|
|
@ -334,14 +336,14 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets dirty when value changed', async () => {
|
it('sets dirty when value changed', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
||||||
expect(fieldset.dirty).to.equal(true);
|
expect(fieldset.dirty).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets touched when field left after focus', async () => {
|
it('sets touched when field left after focus', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
await triggerFocusFor(fieldset.formElements['gender[]'][0].inputElement);
|
await triggerFocusFor(fieldset.formElements['gender[]'][0].inputElement);
|
||||||
await triggerBlurFor(fieldset.formElements['gender[]'][0].inputElement);
|
await triggerBlurFor(fieldset.formElements['gender[]'][0].inputElement);
|
||||||
|
|
@ -349,7 +351,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets a class "state-(touched|dirty)"', async () => {
|
it('sets a class "state-(touched|dirty)"', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements.color.touched = true;
|
fieldset.formElements.color.touched = true;
|
||||||
await fieldset.updateComplete;
|
await fieldset.updateComplete;
|
||||||
|
|
@ -364,7 +366,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets prefilled when field left and value non-empty', async () => {
|
it('sets prefilled when field left and value non-empty', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'football' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'football' };
|
||||||
|
|
@ -385,17 +387,17 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('sets prefilled once instantiated', async () => {
|
it('sets prefilled once instantiated', async () => {
|
||||||
// no prefilled when nothing has value
|
// no prefilled when nothing has value
|
||||||
const fieldsetNotPrefilled = await fixture(html`<${tag}>${inputSlotString}</${tag}>`);
|
const fieldsetNotPrefilled = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
expect(fieldsetNotPrefilled.prefilled).to.equal(false, 'not prefilled on init');
|
expect(fieldsetNotPrefilled.prefilled).to.equal(false, 'not prefilled on init');
|
||||||
|
|
||||||
// prefilled when at least one child has value
|
// prefilled when at least one child has value
|
||||||
const fieldsetPrefilled = await fixture(html`
|
const fieldsetPrefilled = await fixture(html`
|
||||||
<${tag}>
|
<${tag}>
|
||||||
<lion-input name="gender[]" .modelValue=${prefilledModelValue}></lion-input>
|
<${childTag} name="gender[]" .modelValue=${prefilledModelValue}></${childTag}>
|
||||||
<lion-input name="gender[]"></lion-input>
|
<${childTag} name="gender[]"></${childTag}>
|
||||||
<lion-input name="color"></lion-input>
|
<${childTag} name="color"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
<lion-input name="hobbies[]"></lion-input>
|
<${childTag} name="hobbies[]"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
@ -405,7 +407,7 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
describe('serialize', () => {
|
describe('serialize', () => {
|
||||||
it('use form elements serializedValue', async () => {
|
it('use form elements serializedValue', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].serializer = v => `${v.value}-serialized`;
|
fieldset.formElements['hobbies[]'][0].serializer = v => `${v.value}-serialized`;
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'Bar' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'Bar' };
|
||||||
|
|
@ -422,7 +424,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('form elements which are not disabled', async () => {
|
it('form elements which are not disabled', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements.color.modelValue = { checked: false, value: 'blue' };
|
fieldset.formElements.color.modelValue = { checked: false, value: 'blue' };
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: true, value: 'football' };
|
||||||
|
|
@ -445,11 +447,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows for nested fieldsets', async () => {
|
it('allows for nested fieldsets', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset name="userData">
|
<${tag} name="userData">
|
||||||
<lion-input name="comment"></lion-input>
|
<${childTag} name="comment"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
const newFieldset = fieldset.querySelector('lion-fieldset');
|
const newFieldset = fieldset.querySelector('lion-fieldset');
|
||||||
|
|
@ -472,11 +474,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will exclude form elements within an disabled fieldset', async () => {
|
it('will exclude form elements within an disabled fieldset', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset name="userData">
|
<${tag} name="userData">
|
||||||
<lion-input name="comment"></lion-input>
|
<${childTag} name="comment"></${childTag}>
|
||||||
<${tagString} name="newfieldset">${inputSlotString}</${tagString}>
|
<${tag} name="newfieldset">${inputSlots}</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
||||||
|
|
@ -509,7 +511,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('treats names with ending [] as arrays', async () => {
|
it('treats names with ending [] as arrays', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
||||||
|
|
@ -524,11 +526,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not serialize undefined values (nb radios/checkboxes are always serialized)', async () => {
|
it('does not serialize undefined values (nb radios/checkboxes are always serialized)', async () => {
|
||||||
const fieldset = await fixture(`
|
const fieldset = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input name="custom[]"></lion-input>
|
<${childTag} name="custom[]"></${childTag}>
|
||||||
<lion-input name="custom[]"></lion-input>
|
<${childTag} name="custom[]"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['custom[]'][0].modelValue = 'custom 1';
|
fieldset.formElements['custom[]'][0].modelValue = 'custom 1';
|
||||||
|
|
@ -543,9 +545,9 @@ describe('<lion-fieldset>', () => {
|
||||||
describe('reset', () => {
|
describe('reset', () => {
|
||||||
it('restores default values if changes were made', async () => {
|
it('restores default values if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input id="firstName" name="firstName" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.querySelector('lion-input').updateComplete;
|
await el.querySelector('lion-input').updateComplete;
|
||||||
|
|
||||||
|
|
@ -562,9 +564,9 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('restores default values of arrays if changes were made', async () => {
|
it('restores default values of arrays if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-input id="firstName" name="firstName[]" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName[]" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.querySelector('lion-input').updateComplete;
|
await el.querySelector('lion-input').updateComplete;
|
||||||
|
|
||||||
|
|
@ -581,11 +583,11 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
it('restores default values of a nested fieldset if changes were made', async () => {
|
it('restores default values of a nested fieldset if changes were made', async () => {
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<lion-fieldset>
|
<${tag}>
|
||||||
<lion-fieldset id="name" name="name[]">
|
<${tag} id="name" name="name[]">
|
||||||
<lion-input id="firstName" name="firstName" .modelValue="${'Foo'}"></lion-input>
|
<${childTag} id="firstName" name="firstName" .modelValue="${'Foo'}"></${childTag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
el.querySelector('lion-fieldset').updateComplete,
|
el.querySelector('lion-fieldset').updateComplete,
|
||||||
|
|
@ -607,7 +609,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears interaction state', async () => {
|
it('clears interaction state', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
// Safety check initially
|
// Safety check initially
|
||||||
fieldset._setValueForAllFormElements('dirty', true);
|
fieldset._setValueForAllFormElements('dirty', true);
|
||||||
|
|
@ -636,7 +638,7 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears submitted state', async () => {
|
it('clears submitted state', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.submitted = true;
|
fieldset.submitted = true;
|
||||||
fieldset.resetGroup();
|
fieldset.resetGroup();
|
||||||
|
|
@ -656,8 +658,8 @@ describe('<lion-fieldset>', () => {
|
||||||
|
|
||||||
const el = await fixture(html`
|
const el = await fixture(html`
|
||||||
<${tag} .errorValidators=${[[containsA]]}>
|
<${tag} .errorValidators=${[[containsA]]}>
|
||||||
<lion-input name="color" .errorValidators=${[[isCat]]}></lion-input>
|
<${childTag} name="color" .errorValidators=${[[isCat]]}></${childTag}>
|
||||||
<lion-input name="color2"></lion-input>
|
<${childTag} name="color2"></${childTag}>
|
||||||
</${tag}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
await el.registrationReady;
|
await el.registrationReady;
|
||||||
|
|
@ -678,6 +680,68 @@ describe('<lion-fieldset>', () => {
|
||||||
expect(el.error.containsA).to.be.true;
|
expect(el.error.containsA).to.be.true;
|
||||||
expect(el.formElements.color.errorState).to.be.false;
|
expect(el.formElements.color.errorState).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('has access to `_initialModelValue` based on initial children states', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'bar1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
await el.updateComplete;
|
||||||
|
el.modelValue['child[]'] = ['foo2', 'bar2'];
|
||||||
|
expect(el._initialModelValue['child[]']).to.eql(['foo1', 'bar1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not wrongly recompute `_initialModelValue` after dynamic changes of children', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag}>
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
el.modelValue['child[]'] = ['foo2'];
|
||||||
|
const childEl = await fixture(html`
|
||||||
|
<${childTag} name="child[]" .modelValue="${'bar1'}">
|
||||||
|
</${childTag}>
|
||||||
|
`);
|
||||||
|
el.appendChild(childEl);
|
||||||
|
expect(el._initialModelValue['child[]']).to.eql(['foo1', 'bar1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('resetGroup method', () => {
|
||||||
|
it('calls resetGroup on children fieldsets', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} name="parentFieldset">
|
||||||
|
<${tag} name="childFieldset">
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
const childFieldsetEl = el.querySelector(tagString);
|
||||||
|
const resetGroupSpy = sinon.spy(childFieldsetEl, 'resetGroup');
|
||||||
|
el.resetGroup();
|
||||||
|
expect(resetGroupSpy.callCount).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls reset on children fields', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} name="parentFieldset">
|
||||||
|
<${tag} name="childFieldset">
|
||||||
|
<${childTag} name="child[]" .modelValue="${'foo1'}">
|
||||||
|
</${childTag}>
|
||||||
|
</${tag}>
|
||||||
|
</${tag}>
|
||||||
|
`);
|
||||||
|
const childFieldsetEl = el.querySelector(childTagString);
|
||||||
|
const resetSpy = sinon.spy(childFieldsetEl, 'reset');
|
||||||
|
el.resetGroup();
|
||||||
|
expect(resetSpy.callCount).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('a11y', () => {
|
describe('a11y', () => {
|
||||||
|
|
@ -686,7 +750,7 @@ describe('<lion-fieldset>', () => {
|
||||||
// });
|
// });
|
||||||
|
|
||||||
it('has role="group" set', async () => {
|
it('has role="group" set', async () => {
|
||||||
const fieldset = await fixture(`<${tagString}>${inputSlotString}</${tagString}>`);
|
const fieldset = await fixture(html`<${tag}>${inputSlots}</${tag}>`);
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
fieldset.formElements['hobbies[]'][0].modelValue = { checked: false, value: 'chess' };
|
||||||
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
fieldset.formElements['hobbies[]'][1].modelValue = { checked: false, value: 'rugby' };
|
||||||
|
|
@ -698,11 +762,11 @@ describe('<lion-fieldset>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has an aria-labelledby from element with slot="label"', async () => {
|
it('has an aria-labelledby from element with slot="label"', async () => {
|
||||||
const el = await fixture(`
|
const el = await fixture(html`
|
||||||
<${tagString}>
|
<${tag}>
|
||||||
<label slot="label">My Label</label>
|
<label slot="label">My Label</label>
|
||||||
${inputSlotString}
|
${inputSlots}
|
||||||
</${tagString}>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
const label = el.querySelector('[slot="label"]');
|
const label = el.querySelector('[slot="label"]');
|
||||||
expect(el.hasAttribute('aria-labelledby')).to.equal(true);
|
expect(el.hasAttribute('aria-labelledby')).to.equal(true);
|
||||||
|
|
@ -724,40 +788,40 @@ describe('<lion-fieldset>', () => {
|
||||||
childAriaFixture = async (
|
childAriaFixture = async (
|
||||||
msgSlotType = 'feedback', // eslint-disable-line no-shadow
|
msgSlotType = 'feedback', // eslint-disable-line no-shadow
|
||||||
) => {
|
) => {
|
||||||
const dom = await fixture(`
|
const dom = await fixture(html`
|
||||||
<lion-fieldset name="l1_g">
|
<${tag} name="l1_g">
|
||||||
<lion-input name="l1_fa">
|
<${childTag} name="l1_fa">
|
||||||
<div slot="${msgSlotType}" id="msg_l1_fa"></div>
|
<div slot="${msgSlotType}" id="msg_l1_fa"></div>
|
||||||
<!-- field referred by: #msg_l1_fa (local), #msg_l1_g (parent/group) -->
|
<!-- field referred by: #msg_l1_fa (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<lion-input name="l1_fb">
|
<${childTag} name="l1_fb">
|
||||||
<div slot="${msgSlotType}" id="msg_l1_fb"></div>
|
<div slot="${msgSlotType}" id="msg_l1_fb"></div>
|
||||||
<!-- field referred by: #msg_l1_fb (local), #msg_l1_g (parent/group) -->
|
<!-- field referred by: #msg_l1_fb (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<!-- [ INNER FIELDSET ] -->
|
<!-- [ INNER FIELDSET ] -->
|
||||||
|
|
||||||
<lion-fieldset name="l2_g">
|
<${tag} name="l2_g">
|
||||||
<lion-input name="l2_fa">
|
<${childTag} name="l2_fa">
|
||||||
<div slot="${msgSlotType}" id="msg_l2_fa"></div>
|
<div slot="${msgSlotType}" id="msg_l2_fa"></div>
|
||||||
<!-- field referred by: #msg_l2_fa (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
<!-- field referred by: #msg_l2_fa (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<lion-input name="l2_fb">
|
<${childTag} name="l2_fb">
|
||||||
<div slot="${msgSlotType}" id="msg_l2_fb"></div>
|
<div slot="${msgSlotType}" id="msg_l2_fb"></div>
|
||||||
<!-- field referred by: #msg_l2_fb (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
<!-- field referred by: #msg_l2_fb (local), #msg_l2_g (parent/group), #msg_l1_g (grandparent/group.group) -->
|
||||||
</lion-input>
|
</${childTag}>
|
||||||
|
|
||||||
<div slot="${msgSlotType}" id="msg_l2_g"></div>
|
<div slot="${msgSlotType}" id="msg_l2_g"></div>
|
||||||
<!-- group referred by: #msg_l2_g (local), #msg_l1_g (parent/group) -->
|
<!-- group referred by: #msg_l2_g (local), #msg_l1_g (parent/group) -->
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
|
|
||||||
<!-- [ / INNER FIELDSET ] -->
|
<!-- [ / INNER FIELDSET ] -->
|
||||||
|
|
||||||
<div slot="${msgSlotType}" id="msg_l1_g"></div>
|
<div slot="${msgSlotType}" id="msg_l1_g"></div>
|
||||||
<!-- group referred by: #msg_l1_g (local) -->
|
<!-- group referred by: #msg_l1_g (local) -->
|
||||||
</lion-fieldset>
|
</${tag}>
|
||||||
`);
|
`);
|
||||||
return dom;
|
return dom;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue