Skip to content

Commit 91b3858

Browse files
committed
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 angular#2614 Closes angular#5960
1 parent e020916 commit 91b3858

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

src/ng/directive/input.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ function validate(ctrl, validatorName, validity, value){
405405
}
406406

407407
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
408+
var lastValue = element.val();
409+
var lastPlaceholder = element[0].placeholder;
408410
// In composition mode, users are still inputing intermediate text buffer,
409411
// hold the listener until composition is done.
410412
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
@@ -420,17 +422,24 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
420422
});
421423
}
422424

423-
var listener = function() {
425+
var listener = function(event) {
424426
if (composing) return;
425427
var value = element.val();
426428

429+
if (msie && event && event.type === 'input' && !value && value === lastValue &&
430+
element[0].placeholder !== lastPlaceholder) {
431+
lastPlaceholder = element[0].placeholder;
432+
return;
433+
}
434+
427435
// By default we will trim the value
428436
// If the attribute ng-trim exists we will avoid trimming
429437
// e.g. <input ng-model="foo" ng-trim="false">
430438
if (toBoolean(attr.ngTrim || 'T')) {
431439
value = trim(value);
432440
}
433441

442+
lastValue = value;
434443
if (ctrl.$viewValue !== value) {
435444
if (scope.$$phase) {
436445
ctrl.$setViewValue(value);

test/ng/directive/inputSpec.js

+37
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,43 @@ describe('input', function() {
509509
});
510510
}
511511

512+
513+
it('should not dirty the model on an input event in response to a placeholder change', inject(function($document) {
514+
var $body = $document.find('body');
515+
compileInput('<input type="text" ng-model="name" name="name" placeholder="{{placeholder}}" />');
516+
$body.append(formElm);
517+
var waited = false;
518+
519+
scope.$apply(function() {
520+
scope.placeholder = "Test";
521+
});
522+
setTimeout(function() { waited = true; }, 500);
523+
524+
waitsFor(function() {
525+
return waited;
526+
}, 1000);
527+
528+
runs(function() {
529+
expect(inputElm.attr('placeholder')).toBe('Test');
530+
expect(inputElm).toBePristine();
531+
waited = false;
532+
scope.$apply(function() {
533+
scope.placeholder = "Test Again";
534+
});
535+
setTimeout(function() { waited = true; }, 500);
536+
537+
waitsFor(function() {
538+
return waited;
539+
}, 1000);
540+
runs(function() {
541+
expect(inputElm.attr('placeholder')).toBe('Test Again');
542+
expect(inputElm).toBePristine();
543+
inputElm.remove();
544+
});
545+
});
546+
}));
547+
548+
512549
describe('"change" event', function() {
513550
function assertBrowserSupportsChangeEvent(inputEventSupported) {
514551
// Force browser to report a lack of an 'input' event

0 commit comments

Comments
 (0)