fix(form-core): dedupe click event label choice inputs

This commit is contained in:
Joren Broekema 2021-01-19 13:29:22 +01:00
parent 9aaf8959d5
commit 771147537a
4 changed files with 51 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/form-core': patch
---
Stop propagation of label click event in choice inputs to deduplicate the click event on the choice input.

View file

@ -128,6 +128,7 @@ const ChoiceInputMixinImplementation = superclass =>
super();
this.modelValue = { value: '', checked: false };
this.disabled = false;
this._preventDuplicateLabelClick = this._preventDuplicateLabelClick.bind(this);
this.__toggleChecked = this.__toggleChecked.bind(this);
}
@ -189,14 +190,37 @@ const ChoiceInputMixinImplementation = superclass =>
connectedCallback() {
super.connectedCallback();
if (this._labelNode) {
this._labelNode.addEventListener('click', this._preventDuplicateLabelClick);
}
this.addEventListener('user-input-changed', this.__toggleChecked);
}
disconnectedCallback() {
super.disconnectedCallback();
if (this._labelNode) {
this._labelNode.removeEventListener('click', this._preventDuplicateLabelClick);
}
this.removeEventListener('user-input-changed', this.__toggleChecked);
}
/**
* The native platform fires an event for both the click on the label, and also
* the redispatched click on the native input element.
* This results in two click events arriving at the host, but we only want one.
* This method prevents the duplicate click and ensures the correct isTrusted event
* with the correct event.target arrives at the host.
* @param {Event} ev
*/
// eslint-disable-next-line no-unused-vars
_preventDuplicateLabelClick(ev) {
const __inputClickHandler = /** @param {Event} _ev */ _ev => {
_ev.stopImmediatePropagation();
this._inputNode.removeEventListener('click', __inputClickHandler);
};
this._inputNode.addEventListener('click', __inputClickHandler);
}
__toggleChecked() {
if (this.disabled) {
return;

View file

@ -95,6 +95,26 @@ export function runChoiceInputMixinSuite({ tagString } = {}) {
expect(counter).to.equal(1);
});
it('fires one "click" event when clicking label or input, using the right target', async () => {
const spy = sinon.spy();
const el = /** @type {ChoiceInput} */ (await fixture(html`
<${tag}
@click="${spy}"
>
<input slot="input" />
</${tag}>
`));
el.click();
expect(spy.args[0][0].target).to.equal(el);
expect(spy.callCount).to.equal(1);
el._labelNode.click();
expect(spy.args[1][0].target).to.equal(el._labelNode);
expect(spy.callCount).to.equal(2);
el._inputNode.click();
expect(spy.args[2][0].target).to.equal(el._inputNode);
expect(spy.callCount).to.equal(3);
});
it('adds "isTriggerByUser" flag on model-value-changed', async () => {
let isTriggeredByUser;
const el = /** @type {ChoiceInput} */ (await fixture(html`

View file

@ -41,6 +41,8 @@ export declare class ChoiceInputHost {
connectedCallback(): void;
disconnectedCallback(): void;
_preventDuplicateLabelClick(ev: Event): void;
__toggleChecked(): void;
__syncModelCheckedToChecked(checked: boolean): void;