From 91b38581f64ebaa710aac28c06571d7c287e8e13 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Thu, 23 Jan 2014 14:25:14 -0500 Subject: [PATCH] fix(input): don't dirty model when input event triggered due to placeholder 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 --- src/ng/directive/input.js | 11 +++++++++- test/ng/directive/inputSpec.js | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 53a8ddd4d70a..9e518fffb7bd 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -405,6 +405,8 @@ function validate(ctrl, validatorName, validity, value){ } function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + var lastValue = element.val(); + var lastPlaceholder = element[0].placeholder; // In composition mode, users are still inputing intermediate text buffer, // hold the listener until composition is done. // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent @@ -420,10 +422,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { }); } - var listener = function() { + var listener = function(event) { if (composing) return; var value = element.val(); + if (msie && event && event.type === 'input' && !value && value === lastValue && + element[0].placeholder !== lastPlaceholder) { + lastPlaceholder = element[0].placeholder; + return; + } + // By default we will trim the value // If the attribute ng-trim exists we will avoid trimming // e.g. @@ -431,6 +439,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { value = trim(value); } + lastValue = value; if (ctrl.$viewValue !== value) { if (scope.$$phase) { ctrl.$setViewValue(value); diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 668fa0b54a1e..8f13945942bc 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -509,6 +509,43 @@ describe('input', function() { }); } + + it('should not dirty the model on an input event in response to a placeholder change', inject(function($document) { + var $body = $document.find('body'); + compileInput(''); + $body.append(formElm); + var waited = false; + + scope.$apply(function() { + scope.placeholder = "Test"; + }); + setTimeout(function() { waited = true; }, 500); + + waitsFor(function() { + return waited; + }, 1000); + + runs(function() { + expect(inputElm.attr('placeholder')).toBe('Test'); + expect(inputElm).toBePristine(); + waited = false; + scope.$apply(function() { + scope.placeholder = "Test Again"; + }); + setTimeout(function() { waited = true; }, 500); + + waitsFor(function() { + return waited; + }, 1000); + runs(function() { + expect(inputElm.attr('placeholder')).toBe('Test Again'); + expect(inputElm).toBePristine(); + inputElm.remove(); + }); + }); + })); + + describe('"change" event', function() { function assertBrowserSupportsChangeEvent(inputEventSupported) { // Force browser to report a lack of an 'input' event