Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(forms): number input fires valueChanges twice. #36087

Closed

Conversation

TidianeRolland
Copy link
Contributor

Prior to this commit, input field of type number used to fire valueChanges twice. First time after typing in the input field and second time when the input field loses the focus.

PR Close #12540

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Input field of type number emits valueChanges twice. First time after typing in the input field and second time when the input field loses the focus.

Issue Number: #12540

What is the new behavior?

Input field of type number emits valueChanges once.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Copy link
Member

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

  • the linting failure is because you need to format the test file correctly. I setup my VS Code to autorun the clang formatter on every save, which sorts this out
  • also it would be good if we were able to explain, in the commit message, why the (change) event can now be removed; it was obviously included originally for a reason...

@petebacondarwin
Copy link
Member

I think this is the reason... #7557 (comment)

@petebacondarwin
Copy link
Member

According to this we still support IE9 - https://angular.io/guide/browser-support
But I think that in this case there should be a polyfill to cover the problem of input not being triggered...

@TidianeRolland TidianeRolland force-pushed the angular-issue-12540 branch 2 times, most recently from 2da3d40 to 0b4908b Compare March 17, 2020 12:54
@ngbot ngbot bot added this to the needsTriage milestone Mar 18, 2020
@petebacondarwin petebacondarwin added action: review The PR is still awaiting reviews from at least one requested reviewer target: patch This PR is targeted for the next patch release labels Mar 19, 2020
@AndrewKushnir
Copy link
Contributor

AndrewKushnir commented Mar 20, 2020

Hi @TidianeRolland, thanks for the PR!

Could you please provide a bit more information on this change to help me understand the problem better? Currently we fire 2 events: one after typing in the input field (as a result of the oninput event handler) and another one when the input field loses the focus (due to onchange event handler). Having both events fire at the same time is undesirable, but if I understand correctly, removing one of them might be a breaking change (losing focus will no longer trigger value change event, which might be used by developers)? I'm not proposing to keep the change host listener, just want to understand the impact of this change better.

I also started a g3 presubmit for blueprint and a global one (internal only links) to see if this change affects any targets in g3.

Thank you.

@AndrewKushnir AndrewKushnir added the action: presubmit The PR is in need of a google3 presubmit label Mar 20, 2020
@TidianeRolland
Copy link
Contributor Author

Hi @AndrewKushnir thanks for the reply!

Yes, currently we fire 2 events: one after typing in the input field (as a result of the oninput event handler) and another one when the input field loses the focus (due to onchange event handler). Having both events fire at the same time is undesirable and I think having the onchange event trigger just when the input field loses the focus is also undesirable, according to this issue #12540.
Because a lot of developers are subscribing to the valueChanges observable. valueChanges observable emits twice the same value of the input field.

I noticed that we're triggering the change event only for input type number.
The other types of fields aren't concerned.
I think the input event is enough for input type number too.
I hope I explained well.

Thanks for your help

@petebacondarwin
Copy link
Member

My understanding, although it may be lost in the annals of time - perhaps as far back as AngularJS, is that the extra handler was only added to support IE9, which appeared not to trigger the input event on some occasions. But @TidianeRolland was not able to recreate that issue with IE9 now, so it may have been fixed in the browser?

Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TidianeRolland and @petebacondarwin,

Running global TAP indicated that there are few tests in g3 that rely on the change event to be present, here is an example code (simplified) from test harness:

setTextValue(element, text) {
    element.value = text;
    const changeEvent = new Event('change');
    element.dispatchEvent(changeEvent);
}

as a result, form control doesn't pick up an updated value. This is similar to the test that you've added as a part of this PR.

It can probably be refactored to trigger input event instead, but that would require additional time and investigation. I'm marking this PR with the "breaking change" flag, since there might be other cases outside g3 with the same behavior/expectations.

@TidianeRolland I also looked at the original issue report and I think it'd be great to add one more test using Forms API that would replicate original problem (and make sure that only one event is fired), so I set the status of my review to "requested changes".

Thank you.

@atscott
Copy link
Contributor

atscott commented Apr 3, 2020

Thanks to @petebacondarwin for the tip on needing to test IE9 and @gkalpak for helping to test the demo.

It appears that the input event does not fire on IE9 when text in the input is removed via backspace or a cut action. Because IE9 is still a supported browser, I don't think we can merge this change. It would certainly be useful to add a comment about this in the code, noting the change event is needed for IE9 and can be removed when we drop support for it.

@atscott
Copy link
Contributor

atscott commented Apr 3, 2020

What's the contract on the valueChanges event of the forms API? Are we able to change it to pipe through a distinctUntilChanged?

@AndrewKushnir
Copy link
Contributor

@atscott thanks for additional investigation! 👍

Just want to check if this problem only happens in IE9 or also present in IE10/11?

Thank you.

@atscott
Copy link
Contributor

atscott commented Apr 3, 2020

Just want to check if this problem only happens in IE9 or also present in IE10/11?

That's right - I was able to reproduce this missing input event for backspace in a protractor test. The only failure is in IE9, while it passes in chrome, firefox, IE10, and IE11.

@TidianeRolland
Copy link
Contributor Author

Thanks to @petebacondarwin for the tip on needing to test IE9 and @gkalpak for helping to test the demo.

It appears that the input event does not fire on IE9 when text in the input is removed via backspace or a cut action.

@atscott it's really strange because I wasn't able to reproduce this bug using IE9 emulated in IE11 and IE9 on a Windows 7 machine. The input event was triggered

@gkalpak
Copy link
Member

gkalpak commented Apr 3, 2020

@TidianeRolland, fwiw I was able to reproduce it using IE9 emulated in IE11 on Windows 10.
Note that the issue only appears when you delete characters from the value (e.g. hitting backspace or cutting). The input event works fine when typing more characters into the field.

@atscott
Copy link
Contributor

atscott commented Apr 3, 2020

@TidianeRolland can you confirm that backspace/cut does fire the input event for you in IE9? I find it curious that it's working for you but not for me or George. You can use the demo linked above to test this.

@TidianeRolland
Copy link
Contributor Author

TidianeRolland commented Apr 3, 2020

@TidianeRolland can you confirm that backspace/cut does fire the input event for you in IE9? I find it curious that it's working for you but not for me or George. You can use the demo linked above to test this.

I redid my tests. Backspace does not fire input event for emulated IE9.
If I weren't with a friend when I was doing my tests I would have thought I am crazy, because backspace was perfectly working.
@atscott I confirm, stop listening to change event is not a good idea if we're supporting IE9

@atscott
Copy link
Contributor

atscott commented Apr 3, 2020

I redid my tests. Backspace does not fire input event for emulated IE9.

Thanks for retesting that. I'm adding the blocked label on this PR for now. @AndrewKushnir is adding an action item to discuss with the team what the plan is for IE9 support in the future. We'll get back to you with what can be done with this after the discussion.

@atscott
Copy link
Contributor

atscott commented May 1, 2020

Hi @TidianeRolland - We discussed this issue today and decided that we can make this change and add a note in the breaking change on what devs can do if they want to maintain IE9 support.

Please update your commit message to include in your footer:

BREAKING CHANGE: <description> (tests that could break because they rely on 'change' event, requirement for devs to add their own `(change)` listener if they want to support IE9 in the same way it is now, etc)

@atscott atscott modified the milestones: needsTriage, v10-candidates May 1, 2020
@TidianeRolland TidianeRolland force-pushed the angular-issue-12540 branch 4 times, most recently from fd0de03 to 2578b7a Compare May 4, 2020 15:41
@TidianeRolland
Copy link
Contributor Author

Hi @TidianeRolland - We discussed this issue today and decided that we can make this change and add a note in the breaking change on what devs can do if they want to maintain IE9 support.

Please update your commit message to include in your footer:

BREAKING CHANGE: <description> (tests that could break because they rely on 'change' event, requirement for devs to add their own `(change)` listener if they want to support IE9 in the same way it is now, etc)

Hi @atscott - It's done

@atscott atscott added target: major This PR is targeted for the next major release and removed target: patch This PR is targeted for the next patch release labels May 4, 2020
@atscott
Copy link
Contributor

atscott commented May 4, 2020

One of the internal tests failures took me down a deep rabbit hole. It appears that this change may also break some selenium-webdriver tests if you have an old version.

WebElement.clear() (code link) and WebElement.sendKeys (code link) methods call htmlInput.setValueAttribute(""); which, until 2017 (commit reference), would trigger the 'change' event on the input. From what I can tell right now, this means sendKeys and clear would trigger the onChange handler of the number input but no longer do.

Still investigating what can be done to resolve this issue.

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 angular#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 angular#12540
@atscott
Copy link
Contributor

atscott commented May 6, 2020

global presubmit from a few days ago with a rerun of the failing started today. These should all be green now. New TGP scheduled for the 12:00 train.

@atscott atscott removed the action: review The PR is still awaiting reviews from at least one requested reviewer label May 6, 2020
@atscott
Copy link
Contributor

atscott commented May 7, 2020

green TGP

@atscott atscott added action: merge The PR is ready for merge by the caretaker and removed action: presubmit The PR is in need of a google3 presubmit labels May 7, 2020
@alxhub alxhub closed this in 97d6d90 May 7, 2020
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 7, 2020
profanis pushed a commit to profanis/angular that referenced this pull request Sep 5, 2020
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 angular#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 angular#12540

PR Close angular#36087
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: forms breaking changes cla: yes target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Number input fires valueChanges twice
6 participants