Skip to content

Commit

Permalink
feat(toggle): ionChange will only emit from user committed changes (#…
Browse files Browse the repository at this point in the history
…26078)

Co-authored-by: Sean Perkins <sean@ionic.io>
  • Loading branch information
amandaejohnston and sean-perkins committed Oct 10, 2022
1 parent e2cbeeb commit 85d3bd9
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 16 deletions.
5 changes: 5 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>>;
/**
Expand Down
2 changes: 1 addition & 1 deletion angular/test/base/e2e/src/inputs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/**
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/toggle/test/basic/toggle.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
27 changes: 16 additions & 11 deletions core/src/components/toggle/toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand All @@ -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();
Expand All @@ -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,
Expand Down Expand Up @@ -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();
}
}
Expand All @@ -172,7 +177,7 @@ export class Toggle implements ComponentInterface {
ev.preventDefault();

if (this.lastDrag + 300 < Date.now()) {
this.checked = !this.checked;
this.toggleChecked();
}
};

Expand Down

0 comments on commit 85d3bd9

Please sign in to comment.