From c4ec8e47bac2ff230de34d901b0c74e39d2b9ed9 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 21 Mar 2025 12:14:43 -0700 Subject: [PATCH 1/5] fix(range): emit ionInput when value changes --- core/src/components/range/range.tsx | 9 ++++-- .../components/range/test/range-events.e2e.ts | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index b36617ad3e1..8f7efc7c769 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -213,7 +213,12 @@ export class Range implements ComponentInterface { */ @Prop({ mutable: true }) value: RangeValue = 0; @Watch('value') - protected valueChanged() { + protected valueChanged(newVlue: RangeValue, oldValue: RangeValue) { + // The check is necessary because the value can be an object. + if (JSON.stringify(newVlue) !== JSON.stringify(oldValue)) { + this.ionInput.emit({ value: this.value }); + } + if (!this.noUpdate) { this.updateRatio(); } @@ -591,8 +596,6 @@ export class Range implements ComponentInterface { upper: Math.max(valA, valB), }; - this.ionInput.emit({ value: this.value }); - this.noUpdate = false; } diff --git a/core/src/components/range/test/range-events.e2e.ts b/core/src/components/range/test/range-events.e2e.ts index bfbdfac48e4..75b139c3bd5 100644 --- a/core/src/components/range/test/range-events.e2e.ts +++ b/core/src/components/range/test/range-events.e2e.ts @@ -217,6 +217,37 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => expect(ionInputSpy).toHaveReceivedEvent(); }); + test('should not emit when the value does not change', async ({ page }) => { + /** + * Requires padding to prevent the knob from being clipped. + * If it's clipped, then the value might be one off. + * For example, if the knob is clipped on the right, then the value + * will be 99 instead of 100. + */ + await page.setContent( + ` +
+ +
+ `, + config + ); + + const rangeHandle = page.locator('ion-range .range-knob-handle'); + const ionInputSpy = await page.spyOnEvent('ionInput'); + + const rangeHandleBoundingBox = await rangeHandle.boundingBox(); + const x = rangeHandleBoundingBox!.width / 2; + const y = rangeHandleBoundingBox!.height / 2; + + // Click in the middle of the knob to prevent the knob from moving. + await rangeHandle.click({ + position: { x, y }, + }); + + expect(ionInputSpy).not.toHaveReceivedEvent(); + }); + test('should emit when the knob is moved with the keyboard', async ({ page }) => { await page.setContent(``, config); From 8ed08fcba59c9fde5c6d08d721fd1d00642de4f9 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 21 Mar 2025 13:05:56 -0700 Subject: [PATCH 2/5] docs(range): add GitHub issue --- core/src/components/range/test/range-events.e2e.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/components/range/test/range-events.e2e.ts b/core/src/components/range/test/range-events.e2e.ts index 75b139c3bd5..f76d147627b 100644 --- a/core/src/components/range/test/range-events.e2e.ts +++ b/core/src/components/range/test/range-events.e2e.ts @@ -217,7 +217,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => expect(ionInputSpy).toHaveReceivedEvent(); }); - test('should not emit when the value does not change', async ({ page }) => { + test('should not emit when the value does not change', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'https://github.com/ionic-team/ionic-framework/issues/29619', + }); + /** * Requires padding to prevent the knob from being clipped. * If it's clipped, then the value might be one off. From e8b57c838b5c7d9658f86530a886c16236fd1c7e Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 21 Mar 2025 15:39:57 -0700 Subject: [PATCH 3/5] refactor(range): remove stringify usage --- core/src/components/range/range.tsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index 8f7efc7c769..1ae428893a1 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -213,9 +213,9 @@ export class Range implements ComponentInterface { */ @Prop({ mutable: true }) value: RangeValue = 0; @Watch('value') - protected valueChanged(newVlue: RangeValue, oldValue: RangeValue) { - // The check is necessary because the value can be an object. - if (JSON.stringify(newVlue) !== JSON.stringify(oldValue)) { + protected valueChanged(newValue: RangeValue, oldValue: RangeValue) { + const valuesChanged = this.areValuesDifferent(newValue, oldValue); + if (valuesChanged) { this.ionInput.emit({ value: this.value }); } @@ -224,6 +224,21 @@ export class Range implements ComponentInterface { } } + /** + * Compares two RangeValue inputs to determine if they are different. + * + * @param newVal - The new value. + * @param oldVal - The old value. + * @returns `true` if the values are different, `false` otherwise. + */ + private areValuesDifferent = (newVal: RangeValue, oldVal: RangeValue) => { + if (typeof newVal === 'object' && typeof oldVal === 'object') { + return newVal.lower !== oldVal.lower || newVal.upper !== oldVal.upper; + } + + return newVal !== oldVal; + }; + private clampBounds = (value: any): number => { return clamp(this.min, value, this.max); }; From f7ad2ba7b76fd47213f38a257dfa4c516ae3d854 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Mon, 24 Mar 2025 13:52:21 -0700 Subject: [PATCH 4/5] Update core/src/components/range/range.tsx Co-authored-by: Brandy Smith --- core/src/components/range/range.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index 1ae428893a1..9a42d56d964 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -231,7 +231,7 @@ export class Range implements ComponentInterface { * @param oldVal - The old value. * @returns `true` if the values are different, `false` otherwise. */ - private areValuesDifferent = (newVal: RangeValue, oldVal: RangeValue) => { + private compareValues = (newVal: RangeValue, oldVal: RangeValue) => { if (typeof newVal === 'object' && typeof oldVal === 'object') { return newVal.lower !== oldVal.lower || newVal.upper !== oldVal.upper; } From 812d7674efe63983441e39e0b613a864bfcd0f56 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Mon, 24 Mar 2025 13:53:37 -0700 Subject: [PATCH 5/5] fix(range): use correct function --- core/src/components/range/range.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index 9a42d56d964..478b2a57e2e 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -214,7 +214,7 @@ export class Range implements ComponentInterface { @Prop({ mutable: true }) value: RangeValue = 0; @Watch('value') protected valueChanged(newValue: RangeValue, oldValue: RangeValue) { - const valuesChanged = this.areValuesDifferent(newValue, oldValue); + const valuesChanged = this.compareValues(newValue, oldValue); if (valuesChanged) { this.ionInput.emit({ value: this.value }); }