feat(input): ionChange will only emit from user committed changes (#25858)

Resolves #20106, #20061
This commit is contained in:
Sean Perkins
2022-09-12 15:35:43 -04:00
committed by GitHub
parent ba6b539675
commit 8732b7bdb7
18 changed files with 225 additions and 30 deletions

View File

@ -25,6 +25,6 @@ export class BooleanValueAccessorDirective extends ValueAccessor {
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any): void {
this.handleChangeEvent(el, el.checked);
this.handleValueChange(el, el.checked);
}
}

View File

@ -0,0 +1,5 @@
export * from './boolean-value-accessor';
export * from './numeric-value-accessor';
export * from './radio-value-accessor';
export * from './select-value-accessor';
export * from './text-value-accessor';

View File

@ -18,13 +18,13 @@ export class NumericValueAccessorDirective extends ValueAccessor {
super(injector, el);
}
@HostListener('ionChange', ['$event.target'])
_handleIonChange(el: any): void {
this.handleChangeEvent(el, el.value);
@HostListener('ionInput', ['$event.target'])
handleInputEvent(el: HTMLIonInputElement): void {
this.handleValueChange(el, el.value);
}
registerOnChange(fn: (_: number | null) => void): void {
super.registerOnChange((value) => {
super.registerOnChange((value: string) => {
fn(value === '' ? null : parseFloat(value));
});
}

View File

@ -21,6 +21,6 @@ export class RadioValueAccessorDirective extends ValueAccessor {
@HostListener('ionSelect', ['$event.target'])
_handleIonSelect(el: any): void {
this.handleChangeEvent(el, el.checked);
this.handleValueChange(el, el.checked);
}
}

View File

@ -21,6 +21,6 @@ export class SelectValueAccessorDirective extends ValueAccessor {
@HostListener('ionChange', ['$event.target'])
_handleChangeEvent(el: any): void {
this.handleChangeEvent(el, el.value);
this.handleValueChange(el, el.value);
}
}

View File

@ -5,7 +5,7 @@ import { ValueAccessor } from './value-accessor';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ion-input:not([type=number]),ion-textarea,ion-searchbar',
selector: 'ion-textarea,ion-searchbar',
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -21,6 +21,27 @@ export class TextValueAccessorDirective extends ValueAccessor {
@HostListener('ionChange', ['$event.target'])
_handleInputEvent(el: any): void {
this.handleChangeEvent(el, el.value);
this.handleValueChange(el, el.value);
}
}
@Directive({
selector: 'ion-input:not([type=number])',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: InputValueAccessorDirective,
multi: true,
},
],
})
export class InputValueAccessorDirective extends ValueAccessor {
constructor(injector: Injector, el: ElementRef) {
super(injector, el);
}
@HostListener('ionInput', ['$event.target'])
_handleInputEvent(el: any): void {
this.handleValueChange(el, el.value);
}
}

View File

@ -29,7 +29,20 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
setIonicClasses(this.el);
}
handleChangeEvent(el: HTMLElement, value: any): void {
/**
* Notifies the ControlValueAccessor of a change in the value of the control.
*
* This is called by each of the ValueAccessor directives when we want to update
* the status and validity of the form control. For example with text components this
* is called when the ionInput event is fired. For select components this is called
* when the ionChange event is fired.
*
* This also updates the Ionic form status classes on the element.
*
* @param el The component element.
* @param value The new value of the control.
*/
handleValueChange(el: HTMLElement, value: any): void {
if (el === this.el.nativeElement) {
if (value !== this.lastValue) {
this.lastValue = value;