From 0854a11a25759d0201eae66c96a62fe138d486f8 Mon Sep 17 00:00:00 2001 From: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:18:53 -0500 Subject: [PATCH] fix(angular,vue): range form value updates while dragging knob (#28422) Issue number: Resolves #28256 --------- ## What is the current behavior? In the form integrations for Angular and Vue, the value of a range does not update while the knob is actively being dragged, only when the knob is released. ## What is the new behavior? The form integrations now update the range's value when the `ionInput` event fires, rather than `ionChange`. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information I wasn't sure how to add reliable automated tests for this behavior. The difference only applies when actively dragging the knob, and we've had issues with such gestures being flaky in the past. I did add value displays to the test apps so the behavior can be manually tested. --- core/stencil.config.ts | 4 +- .../select-value-accessor.ts | 9 +--- .../text-value-accessor.ts | 7 ++- .../standalone/src/directives/range.ts | 4 +- .../form-controls/range/range.component.html | 1 + packages/vue/src/proxies.ts | 2 +- packages/vue/test/base/src/router/index.ts | 4 ++ .../vue/test/base/src/views/Components.vue | 3 ++ packages/vue/test/base/src/views/Range.vue | 53 +++++++++++++++++++ 9 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 packages/vue/test/base/src/views/Range.vue diff --git a/core/stencil.config.ts b/core/stencil.config.ts index 0107c8f76b..b3c2eec650 100644 --- a/core/stencil.config.ts +++ b/core/stencil.config.ts @@ -201,13 +201,13 @@ export const config: Config = { externalEvent: 'ionChange' }, { - elements: ['ion-datetime', 'ion-radio-group', 'ion-radio', 'ion-range', 'ion-segment', 'ion-segment-button', 'ion-select', 'ion-accordion-group'], + elements: ['ion-datetime', 'ion-radio-group', 'ion-radio', 'ion-segment', 'ion-segment-button', 'ion-select', 'ion-accordion-group'], targetAttr: 'value', event: 'v-ion-change', externalEvent: 'ionChange' }, { - elements: ['ion-input', 'ion-searchbar', 'ion-textarea'], + elements: ['ion-input', 'ion-searchbar', 'ion-textarea', 'ion-range'], targetAttr: 'value', event: 'v-ion-input', externalEvent: 'ionInput' diff --git a/packages/angular/src/directives/control-value-accessors/select-value-accessor.ts b/packages/angular/src/directives/control-value-accessors/select-value-accessor.ts index 7e2683edaf..254d4bac3a 100644 --- a/packages/angular/src/directives/control-value-accessors/select-value-accessor.ts +++ b/packages/angular/src/directives/control-value-accessors/select-value-accessor.ts @@ -4,7 +4,7 @@ import { ValueAccessor } from '@ionic/angular/common'; @Directive({ /* tslint:disable-next-line:directive-selector */ - selector: 'ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime', + selector: 'ion-select, ion-radio-group, ion-segment, ion-datetime', providers: [ { provide: NG_VALUE_ACCESSOR, @@ -20,12 +20,7 @@ export class SelectValueAccessorDirective extends ValueAccessor { @HostListener('ionChange', ['$event.target']) _handleChangeEvent( - el: - | HTMLIonRangeElement - | HTMLIonSelectElement - | HTMLIonRadioGroupElement - | HTMLIonSegmentElement - | HTMLIonDatetimeElement + el: HTMLIonSelectElement | HTMLIonRadioGroupElement | HTMLIonSegmentElement | HTMLIonDatetimeElement ): void { this.handleValueChange(el, el.value); } diff --git a/packages/angular/src/directives/control-value-accessors/text-value-accessor.ts b/packages/angular/src/directives/control-value-accessors/text-value-accessor.ts index f4b52198cf..14395dfeb4 100644 --- a/packages/angular/src/directives/control-value-accessors/text-value-accessor.ts +++ b/packages/angular/src/directives/control-value-accessors/text-value-accessor.ts @@ -2,8 +2,9 @@ import { ElementRef, Injector, Directive, HostListener } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; +// TODO(FW-5495): rename class since range isn't a text component @Directive({ - selector: 'ion-input:not([type=number]),ion-textarea,ion-searchbar', + selector: 'ion-input:not([type=number]),ion-textarea,ion-searchbar,ion-range', providers: [ { provide: NG_VALUE_ACCESSOR, @@ -18,7 +19,9 @@ export class TextValueAccessorDirective extends ValueAccessor { } @HostListener('ionInput', ['$event.target']) - _handleInputEvent(el: HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSearchbarElement): void { + _handleInputEvent( + el: HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSearchbarElement | HTMLIonRangeElement + ): void { this.handleValueChange(el, el.value); } } diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index f77beecbe4..2195d06f6c 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -88,8 +88,8 @@ export class IonRange extends ValueAccessor implements OnInit { proxyInputs(IonRange, RANGE_INPUTS); } - @HostListener('ionChange', ['$event.target']) - handleIonChange(el: HTMLIonRangeElement): void { + @HostListener('ionInput', ['$event.target']) + handleIonInput(el: HTMLIonRangeElement): void { this.handleValueChange(el, el.value); } } diff --git a/packages/angular/test/base/src/app/lazy/form-controls/range/range.component.html b/packages/angular/test/base/src/app/lazy/form-controls/range/range.component.html index 2dab1a129c..e57be8c060 100644 --- a/packages/angular/test/base/src/app/lazy/form-controls/range/range.component.html +++ b/packages/angular/test/base/src/app/lazy/form-controls/range/range.component.html @@ -11,6 +11,7 @@
Range
+

Value: {{ form.controls['range'].value }}

Submit diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index 0cfc606724..de9aebb8b9 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -630,7 +630,7 @@ export const IonRange = /*@__PURE__*/ defineContainer('ion-refresher', defineIonRefresher, [ diff --git a/packages/vue/test/base/src/router/index.ts b/packages/vue/test/base/src/router/index.ts index a62a9ceefb..f55aec808a 100644 --- a/packages/vue/test/base/src/router/index.ts +++ b/packages/vue/test/base/src/router/index.ts @@ -82,6 +82,10 @@ const routes: Array = [ path: '/components/select', component: () => import('@/views/Select.vue') }, + { + path: '/components/range', + component: () => import('@/views/Range.vue') + }, { path: '/nested', component: () => import('@/views/RouterOutlet.vue'), diff --git a/packages/vue/test/base/src/views/Components.vue b/packages/vue/test/base/src/views/Components.vue index 84c30f9b67..cad54df363 100644 --- a/packages/vue/test/base/src/views/Components.vue +++ b/packages/vue/test/base/src/views/Components.vue @@ -8,6 +8,9 @@ Select + + Range + diff --git a/packages/vue/test/base/src/views/Range.vue b/packages/vue/test/base/src/views/Range.vue new file mode 100644 index 0000000000..c0d6106140 --- /dev/null +++ b/packages/vue/test/base/src/views/Range.vue @@ -0,0 +1,53 @@ + + +