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

Already on GitHub? Sign in to your account

IE10 fires input event when a placeholder is defined so that form element is in dirty instead of pristine state #2614

Closed
jupiterplanet opened this Issue May 9, 2013 · 27 comments

Comments

Projects
None yet

Input elements in AngularJS can be in pristine state meaning that the input element's value hasn't been modified yet by the user. In this case error messages can be hidden although validation fails because the input field is empty.

AngularJS uses different measures to determine if the value in an input element has changed. It listens to the input event for all browsers supporting this event with the exception of IE9 as this browser does not implement this event correctly.

However, as it turns out IE10 also has implementations faults. If a placeholder is defined on an input element IE10 fires this event when the placeholder is set during DOM loading and when it is removed when the user clicks into the input field so that error messages which depend on the pristine condition are displayed although the user has not yet modified the input's value.

Open the following plunk with IE10 to see this behavior:
http://plnkr.co/LqlkhtIPPEwgP0znR7vz

Click into the e-mail input field and the error message displays although the input's value has not changed yet.

In all other browsers (Chrome, IE9, Firefox) the error message is not displayed.

A workaround is to not use the input event just like for IE9.

config(['$provide', function($provide) {
        $provide.decorator('$sniffer', ['$delegate', function($sniffer) {
            var msie = parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
            var _hasEvent = $sniffer.hasEvent;
            $sniffer.hasEvent = function(event) {
                if (event === 'input' && msie === 10) {
                 return false;
                }    
                _hasEvent.call(this, event);
            }
            return $sniffer;
        }]);
    }]).

This fix works, but is far from good. Is this a browser bug, or a Angular/jQuery bug?

Guuz commented Nov 15, 2013

👍

Looks like it's fixed in IE11, and is browser related.

Guuz commented Nov 15, 2013

I just tested it in IE and its not fixed...
An input element becomes dirty as soon as its focussed. Unlike Chrome for example where you have to type in it first.
A textarea becomes dirty right away without touching it.

may be related to #5025 ?

Better sniff code:

       var broken = false,
            ta = angular.element('<textarea>').on('input', function(evt) {
                broken = true;
            });
        ta.attr('placeholder', 'IESUCKS');

Guuz commented Dec 6, 2013

lol :) nice one @jamie-pate!

BUMP. This really needs to be fixed by the angular team.

Contributor

caitp commented Jan 23, 2014

Angular isn't necessarily capable of fixing bugs in IE, @WalterWeidner. How would you propose fixing it? Do we say "oh, the text value is identical to the value of the placeholder attribute, therefore it must not be a real value lets just ignore it"? Because that approach seems like it would cause much worse problems.

I'll submit a fix for it but honestly I expect any fix for this is going to cause more regressions than the fix was worth

The fix would be to sniff for this problem and not use the input event just like for IE9. (as mentioned at the top of the thread) We all wish that ie10 had actually ended the constant stream of ie workarounds but It seems like they will continue to be needed (though at least the fire hose seems to have been reduced to a garden hose)

I agree that it is an IE problem but I think it would be better for it to be accounted for in angular code rather than in every single user's module configuration. This way the code will be less likely to break when we switch to future versions of angular.

Contributor

caitp commented Jan 23, 2014

The issue with sniffing this is, the event (at least on IE10 standards mode) is not triggered synchronously, and I can't seem to get it to trigger before DOMContentLoaded/onload. So the issue here is that by the time we need to use the sniffed value, it's unavailable (unless text inputs are in templates imported by asynchronous directives).

Further, we have no way of knowing that the input event was triggered by a placeholder, as the input event doesn't give us any feedback about what caused it. So it's probably a lost cause to try to deal with this.

There are so many problems with the entire issue that it's honestly probably not even worth trying. IE10 is still a big chunk of the browser market, but it's on a steep decline, while IE11 is on the rise.

This kind of works, but I have no guarantees that it doesn't break other browsers, and it relies on the UA string so we have no guarantee that it will even fix the issue in every possible configuration of IE.

    if (msie && event && event.type === 'input' && !value && value === lastValue &&
      element.prop('placeholder')) {
      return;
    }

in the listener.

caitp added a commit to caitp/angular.js that referenced this issue Jan 23, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960
Contributor

caitp commented Jan 23, 2014

This is probably "good enough", who wants to dogfood this patch and see if it breaks anything

caitp added a commit to caitp/angular.js that referenced this issue Jan 23, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

caitp added a commit to caitp/angular.js that referenced this issue Jan 23, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

caitp added a commit to caitp/angular.js that referenced this issue Jan 23, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

caitp added a commit to caitp/angular.js that referenced this issue Jan 24, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

Hi Caitlin

I have done some testing on this one and have noticed that the input event fires even though the placeholder attribute has not changed (if the input receives focus and then looses focus the input event fires). An additional conditional check seems to solve the issue, as per line below:

if (msie && (event || noevent).type === 'input' && (element[0].placeholder !== placeholder ||
(element[0].value.length == 0 && element[0].placeholder.length > 0))) {

Contributor

caitp commented Jan 27, 2014

Well originally I was also testing that value === lastValue (which kind of sucks, having to track that). But if it's necessary, that could be done too... Maybe there's a smarter way to do this without relying on hacks though.

Agreed, hopefully there is a more elegant way to cater for the specific use case.

caitp added a commit to caitp/angular.js that referenced this issue Feb 13, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

hey @caitp would that fix land in 1.2.15?

Contributor

caitp commented Mar 20, 2014

Still needs to be reviewed, it's probably become a tad bitrotten by now

This seems to affect IE 11 (tested on Windows 8.1) as well.

@caitp caitp closed this in ff428e7 Apr 18, 2014

caitp added a commit that referenced this issue Apr 18, 2014

fix(input): don't dirty model when input event triggered due to place…
…holder change

Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960

@caitp will this be fixed in 1.2.x branch as well?

Contributor

caitp commented Apr 22, 2014

@deezahyn this was merged into 1.2 and 1.3. There's also a bug report on IE about this behaviour, so perhaps there will eventually be a fix for it. Unfortunately, placeholder change isn't the only time IE sends input events inappropriately.

It will also send an input event if you so much as click on a form control with a placeholder :( So this fix doesn't totally make IE behave normally =(

oops my bad, thought it was only for 1.3.x tag. Will now test 👍 Thanks for the fix @caitp

rsalm added a commit to Opetushallitus/organisaatio that referenced this issue May 8, 2014

I'm still getting some associated problems, It seems like even though it doesn't cause the model to be dirty, it still can update the scope with the viewValue...

This can cause issues if for example ng-model="container.value" container will be created on the current scope, whereas the 'real' container is actually supposed to be on $parent but hasn't been created yet.
Oops, merged in 1.2.17 but using 1.2.16

tgt commented Aug 28, 2014

Sorry to resurface this issue, but this bug still seems to be present for textareas. I'm using AngularJS 1.2.22 and testing in IE 11 on Windows 7.

ognus commented Nov 18, 2014

This issue seams to still be present (input type='text' with placeholder) in IE11 and AngularJS 1.3.2. I haven't tested on IE10 yet. Following hack (coffee script) based on initial @jupiterplanet solution works for me:

.config ($provide) ->
  $provide.decorator '$sniffer', ['$delegate', ($sniffer) ->
    userAgent = navigator.userAgent.toLowerCase()
    msie = parseInt((/msie (\d+)/.exec(userAgent) ? [])[1], 10)
    if isNaN(msie)
      msie = parseInt((/trident\/.*; rv:(\d+)/.exec(userAgent) ? [])[1], 10)
    _hasEvent = $sniffer.hasEvent
    $sniffer.hasEvent = (event) ->
      if event is 'input' and msie >= 10
        return false
      _hasEvent.call this, event
    return $sniffer
  ] 

durz commented Mar 3, 2015

For others who are coming across this issue when using textareas , it appears to have been fixed as of 1.3.6.

Plunker (open in IE): http://plnkr.co/edit/LDZX0GFvq1zchiVGehCU?p=preview

When opened with IE 11.0.9600.17416, change the Angular version in the plunker between 1.3.5 and 1.3.6 and you'll see the form no longer getting set to dirty as of 1.3.6.

vartija added a commit to Opetushallitus/organisaatio that referenced this issue Mar 24, 2016

vartija added a commit to Opetushallitus/organisaatio that referenced this issue Mar 24, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment