feat(toggle): ionChange will only emit from user committed changes (#26078)

Co-authored-by: Sean Perkins <sean@ionic.io>
This commit is contained in:
Amanda Johnston
2022-10-10 09:55:58 -05:00
committed by GitHub
parent e2cbeeb8ac
commit 85d3bd99be
6 changed files with 27 additions and 16 deletions

View File

@ -25,6 +25,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Select](#version-7x-select)
- [Slides](#version-7x-slides)
- [Textarea](#version-7x-textarea)
- [Toggle](#version-7x-toggle)
- [Virtual Scroll](#version-7x-virtual-scroll)
- [JavaScript Frameworks](#version-7x-javascript-frameworks)
- [React](#version-7x-react)
@ -147,6 +148,10 @@ Developers using these components will need to migrate to using Swiper.js direct
- `ionInput` dispatches an event detail of `null` when the textarea is cleared as a result of `clear-on-edit="true"`.
<h4 id="version-7x-toggle">Toggle</h4>
- `ionChange` is no longer emitted when the `checked` property of `ion-toggle` is modified externally. `ionChange` is only emitted from user committed changes, such as clicking the toggle to set it on or off.
<h4 id="version-7x-virtual-scroll">Virtual Scroll</h4>
`ion-virtual-scroll` has been removed from Ionic.

View File

@ -1909,7 +1909,8 @@ export class IonTitle {
import type { ToggleChangeEventDetail as IToggleToggleChangeEventDetail } from '@ionic/core';
export declare interface IonToggle extends Components.IonToggle {
/**
* Emitted when the value property has changed.
* Emitted when the user switches the toggle on or off. Does not emit
when programmatically changing the value of the `checked` property.
*/
ionChange: EventEmitter<CustomEvent<IToggleToggleChangeEventDetail>>;
/**

View File

@ -39,7 +39,7 @@ describe('Inputs', () => {
cy.get('#reset-button').click();
cy.get('ion-checkbox#first-checkbox').click();
cy.get('ion-toggle').invoke('prop', 'checked', true);
cy.get('ion-toggle').first().click();
cy.get('ion-input').eq(0).type('hola');
cy.get('ion-input input').eq(0).blur();

View File

@ -6725,7 +6725,7 @@ declare namespace LocalJSX {
*/
"onIonBlur"?: (event: IonToggleCustomEvent<void>) => void;
/**
* Emitted when the value property has changed.
* Emitted when the user switches the toggle on or off. Does not emit when programmatically changing the value of the `checked` property.
*/
"onIonChange"?: (event: IonToggleCustomEvent<ToggleChangeEventDetail>) => void;
/**

View File

@ -52,14 +52,14 @@ test.describe('toggle: basic', () => {
});
});
test('should fire change event if checked prop is changed directly', async ({ page }) => {
test('should not fire change event if checked prop is changed directly', async ({ page }) => {
const toggle = page.locator('#orange');
const ionChange = await page.spyOnEvent('ionChange');
await toggle.evaluate((el: HTMLIonToggleElement) => (el.checked = true));
await page.waitForChanges();
expect(ionChange).toHaveReceivedEvent();
expect(ionChange).toHaveReceivedEventTimes(0);
});
test('should pass properties down to hidden input', async ({ page }) => {

View File

@ -70,7 +70,8 @@ export class Toggle implements ComponentInterface {
@Prop() enableOnOffLabels: boolean | undefined = undefined;
/**
* Emitted when the value property has changed.
* Emitted when the user switches the toggle on or off. Does not emit
* when programmatically changing the value of the `checked` property.
*/
@Event() ionChange!: EventEmitter<ToggleChangeEventDetail>;
@ -90,14 +91,6 @@ export class Toggle implements ComponentInterface {
*/
@Event() ionStyle!: EventEmitter<StyleEventDetail>;
@Watch('checked')
checkedChanged(isChecked: boolean) {
this.ionChange.emit({
checked: isChecked,
value: this.value,
});
}
@Watch('disabled')
disabledChanged() {
this.emitStyle();
@ -106,6 +99,18 @@ export class Toggle implements ComponentInterface {
}
}
private toggleChecked() {
const { checked, value } = this;
const isNowChecked = !checked;
this.checked = isNowChecked;
this.ionChange.emit({
checked: isNowChecked,
value,
});
}
async connectedCallback() {
this.gesture = (await import('../../utils/gesture')).createGesture({
el: this.el,
@ -146,7 +151,7 @@ export class Toggle implements ComponentInterface {
private onMove(detail: GestureDetail) {
if (shouldToggle(isRTL(this.el), this.checked, detail.deltaX, -10)) {
this.checked = !this.checked;
this.toggleChecked();
hapticSelection();
}
}
@ -172,7 +177,7 @@ export class Toggle implements ComponentInterface {
ev.preventDefault();
if (this.lastDrag + 300 < Date.now()) {
this.checked = !this.checked;
this.toggleChecked();
}
};