fix(switch): dispatch checked-changed on checked change

This commit is contained in:
qa46hx 2020-09-24 13:38:07 +02:00 committed by Thomas Allmer
parent 175e6bea6f
commit 6aacbc4403
4 changed files with 83 additions and 12 deletions

View file

@ -51,12 +51,18 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
return html`${this._inputGroupTemplate()}`; return html`${this._inputGroupTemplate()}`;
} }
constructor() {
super();
this.role = 'switch';
this.checked = false;
this.__handleButtonSwitchCheckedChanged = this.__handleButtonSwitchCheckedChanged.bind(this);
}
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this._inputNode.addEventListener( if (this._inputNode) {
'checked-changed', this._inputNode.addEventListener('checked-changed', this.__handleButtonSwitchCheckedChanged);
this.__handleButtonSwitchCheckedChanged.bind(this), }
);
if (this._labelNode) { if (this._labelNode) {
this._labelNode.addEventListener('click', this.__toggleChecked); this._labelNode.addEventListener('click', this.__toggleChecked);
} }
@ -65,6 +71,12 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
} }
disconnectedCallback() { disconnectedCallback() {
if (this._inputNode) {
this._inputNode.removeEventListener(
'checked-changed',
this.__handleButtonSwitchCheckedChanged,
);
}
if (this._labelNode) { if (this._labelNode) {
this._labelNode.removeEventListener('click', this.__toggleChecked); this._labelNode.removeEventListener('click', this.__toggleChecked);
} }
@ -86,7 +98,6 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
} }
_syncButtonSwitch() { _syncButtonSwitch() {
this._inputNode.checked = this.checked;
this._inputNode.disabled = this.disabled; this._inputNode.disabled = this.disabled;
} }
} }

View file

@ -74,29 +74,43 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
super(); super();
this.role = 'switch'; this.role = 'switch';
this.checked = false; this.checked = false;
this.addEventListener('click', this.__handleToggleStateChange); this.__toggleChecked = this.__toggleChecked.bind(this);
this.addEventListener('keydown', this.__handleKeydown); this.__handleKeydown = this.__handleKeydown.bind(this);
this.addEventListener('keyup', this.__handleKeyup); this.__handleKeyup = this.__handleKeyup.bind(this);
} }
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.setAttribute('aria-checked', `${this.checked}`); this.setAttribute('aria-checked', `${this.checked}`);
this.addEventListener('click', this.__toggleChecked);
this.addEventListener('keydown', this.__handleKeydown);
this.addEventListener('keyup', this.__handleKeyup);
} }
__handleToggleStateChange() { disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('click', this.__toggleChecked);
this.removeEventListener('keydown', this.__handleKeydown);
this.removeEventListener('keyup', this.__handleKeyup);
}
__toggleChecked() {
if (this.disabled) { if (this.disabled) {
return; return;
} }
// Force IE11 to focus the component. // Force IE11 to focus the component.
this.focus(); this.focus();
this.checked = !this.checked; this.checked = !this.checked;
}
__checkedStateChange() {
this.dispatchEvent( this.dispatchEvent(
new Event('checked-changed', { new Event('checked-changed', {
composed: true, composed: true,
bubbles: true, bubbles: true,
}), }),
); );
this.setAttribute('aria-checked', `${this.checked}`);
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
@ -109,7 +123,7 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
__handleKeyup(e) { __handleKeyup(e) {
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) { if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) {
this.__handleToggleStateChange(); this.__toggleChecked();
} }
} }
@ -126,8 +140,8 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
*/ */
requestUpdateInternal(name, oldValue) { requestUpdateInternal(name, oldValue) {
super.requestUpdateInternal(name, oldValue); super.requestUpdateInternal(name, oldValue);
if (this.isConnected && name === 'checked') { if (this.isConnected && name === 'checked' && this.checked !== oldValue) {
this.setAttribute('aria-checked', `${this.checked}`); this.__checkedStateChange();
} }
} }
} }

View file

@ -73,6 +73,23 @@ describe('lion-switch-button', () => {
checkCall(handlerSpy.getCall(1), false); checkCall(handlerSpy.getCall(1), false);
}); });
it('should dispatch "checked-changed" event when checked changed', () => {
const handlerSpy = sinon.spy();
el.addEventListener('checked-changed', handlerSpy);
el.checked = true;
el.checked = false;
expect(handlerSpy.callCount).to.equal(2);
const checkCall = call => {
expect(call.args).to.have.a.lengthOf(1);
const e = call.args[0];
expect(e).to.be.an.instanceof(Event);
expect(e.bubbles).to.be.true;
expect(e.composed).to.be.true;
};
checkCall(handlerSpy.getCall(0), true);
checkCall(handlerSpy.getCall(1), false);
});
it('should not dispatch "checked-changed" event if disabled', () => { it('should not dispatch "checked-changed" event if disabled', () => {
const handlerSpy = sinon.spy(); const handlerSpy = sinon.spy();
el.disabled = true; el.disabled = true;

View file

@ -1,4 +1,5 @@
import { expect, fixture, html } from '@open-wc/testing'; import { expect, fixture, html } from '@open-wc/testing';
import sinon from 'sinon';
import '../lion-switch.js'; import '../lion-switch.js';
describe('lion-switch', () => { describe('lion-switch', () => {
@ -68,6 +69,34 @@ describe('lion-switch', () => {
}); });
}); });
it('should dispatch "checked-changed" event when toggled via button or label', async () => {
const handlerSpy = sinon.spy();
const el = await fixture(html`<lion-switch .choiceValue=${'foo'}></lion-switch>`);
el.addEventListener('checked-changed', handlerSpy);
el._inputNode.click();
el._labelNode.click();
await el.updateComplete;
expect(handlerSpy.callCount).to.equal(2);
const checkCall = call => {
expect(call.args).to.have.a.lengthOf(1);
const e = call.args[0];
expect(e).to.be.an.instanceof(Event);
expect(e.bubbles).to.be.true;
expect(e.composed).to.be.true;
};
checkCall(handlerSpy.getCall(0), true);
checkCall(handlerSpy.getCall(1), false);
});
it('should dispatch "checked-changed" event when checked changed', async () => {
const handlerSpy = sinon.spy();
const el = await fixture(html`<lion-switch .choiceValue=${'foo'}></lion-switch>`);
el.addEventListener('checked-changed', handlerSpy);
el.checked = true;
await el.updateComplete;
expect(handlerSpy.callCount).to.equal(1);
});
it('is submitted by default', async () => { it('is submitted by default', async () => {
const el = await fixture(html`<lion-switch></lion-switch>`); const el = await fixture(html`<lion-switch></lion-switch>`);
expect(el.submitted).to.be.true; expect(el.submitted).to.be.true;