From 97d6d909e7b09ab25822ba6b3c4f9b44a14f54dd Mon Sep 17 00:00:00 2001 From: Tidi Date: Mon, 16 Mar 2020 15:24:53 +0000 Subject: [PATCH] fix(forms): number input fires valueChanges twice. (#36087) Prior to this commit, number input fields would to fire valueChanges twice: once for `input` events when typing and second for the `change` event when the field lost focus (both events happen at once when using the increment and decrement buttons on the number field). Fixes #12540 BREAKING CHANGE: Number inputs no longer listen to the `change` event. * Tests which trigger `change` events need to be updated to trigger `input` events instead. * The `change` event was in place to support IE9, as we found that `input` events were not fired with backspace or cut actions. If you need to maintain IE9 support, you will need to add a change event listener to number inputs and call the `onChange` method of `NumberValueAccessor` manually. * Lastly, old versions of WebDriver would synthetically trigger the `change` event on `WebElement.clear` and `WebElement.sendKeys`. If you are using an old version of WebDriver, you may need to update tests to ensure `input` events are triggered. For example, you could use `element.sendKeys(Keys.chord(Keys.CONTROL, "a"), Keys.BACK_SPACE);` in place of `element.clear()`. PR Close #12540 PR Close #36087 --- .../src/directives/number_value_accessor.ts | 6 +----- .../test/value_accessor_integration_spec.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/forms/src/directives/number_value_accessor.ts b/packages/forms/src/directives/number_value_accessor.ts index dc85ae7b0d..2a2b8e50d1 100644 --- a/packages/forms/src/directives/number_value_accessor.ts +++ b/packages/forms/src/directives/number_value_accessor.ts @@ -43,11 +43,7 @@ export const NUMBER_VALUE_ACCESSOR: any = { @Directive({ selector: 'input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]', - host: { - '(change)': 'onChange($event.target.value)', - '(input)': 'onChange($event.target.value)', - '(blur)': 'onTouched()' - }, + host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'}, providers: [NUMBER_VALUE_ACCESSOR] }) export class NumberValueAccessor implements ControlValueAccessor { diff --git a/packages/forms/test/value_accessor_integration_spec.ts b/packages/forms/test/value_accessor_integration_spec.ts index 852e04bde4..b00207e377 100644 --- a/packages/forms/test/value_accessor_integration_spec.ts +++ b/packages/forms/test/value_accessor_integration_spec.ts @@ -149,6 +149,23 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(control.value).toEqual(0); }); + it('should ignore the change event', () => { + const fixture = initTest(FormControlNumberInput); + const control = new FormControl(); + fixture.componentInstance.control = control; + fixture.detectChanges(); + + control.valueChanges.subscribe({ + next: (value) => { + throw 'Input[number] should not react to change event'; + } + }); + const input = fixture.debugElement.query(By.css('input')); + + input.nativeElement.value = '5'; + dispatchEvent(input.nativeElement, 'change'); + }); + it('when value is cleared programmatically', () => { const fixture = initTest(FormControlNumberInput); const control = new FormControl(10);