mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-23 19:40:56 +08:00
fix(inputs): ignoring input events in IE caused by placeholder changes or focus/blur on inputs with placeholders
Closes #9265
This commit is contained in:
committed by
Caitlin Potter
parent
579aa59324
commit
55d9db56a6
@@ -954,7 +954,6 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
}
|
||||
|
||||
function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
var placeholder = element[0].placeholder, noevent = {};
|
||||
var type = lowercase(element[0].type);
|
||||
|
||||
// In composition mode, users are still inputing intermediate text buffer,
|
||||
@@ -978,15 +977,6 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
var value = element.val(),
|
||||
event = ev && ev.type;
|
||||
|
||||
// IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
|
||||
// We don't want to dirty the value when this happens, so we abort here. Unfortunately,
|
||||
// IE also sends input events for other non-input-related things, (such as focusing on a
|
||||
// form control), so this change is not entirely enough to solve this.
|
||||
if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
|
||||
placeholder = element[0].placeholder;
|
||||
return;
|
||||
}
|
||||
|
||||
// By default we will trim the value
|
||||
// If the attribute ng-trim exists we will avoid trimming
|
||||
// If input type is 'password', the value is never trimmed
|
||||
|
||||
@@ -67,7 +67,9 @@ function $SnifferProvider() {
|
||||
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
||||
// it. In particular the event is not fired when backspace or delete key are pressed or
|
||||
// when cut operation is performed.
|
||||
if (event == 'input' && msie == 9) return false;
|
||||
// IE10+ implements 'input' event but it erroneously fires under various situations,
|
||||
// e.g. when placeholder changes, or a form is focused.
|
||||
if (event === 'input' && msie <= 11) return false;
|
||||
|
||||
if (isUndefined(eventSupport[event])) {
|
||||
var divElm = document.createElement('div');
|
||||
|
||||
@@ -199,7 +199,7 @@ angular.scenario.dsl('binding', function() {
|
||||
*/
|
||||
angular.scenario.dsl('input', function() {
|
||||
var chain = {};
|
||||
var supportInputEvent = 'oninput' in document.createElement('div') && msie != 9;
|
||||
var supportInputEvent = 'oninput' in document.createElement('div') && !(msie && msie <= 11);
|
||||
|
||||
chain.enter = function(value, event) {
|
||||
return this.addFutureAction("input '" + this.name + "' enter '" + value + "'",
|
||||
|
||||
@@ -1549,22 +1549,170 @@ describe('input', function() {
|
||||
expect(scope.name).toEqual('caitp');
|
||||
});
|
||||
|
||||
it('should not dirty the model on an input event in response to a placeholder change', inject(function($sniffer) {
|
||||
if (msie && $sniffer.hasEvent('input')) {
|
||||
compileInput('<input type="text" ng-model="name" name="name" />');
|
||||
inputElm.attr('placeholder', 'Test');
|
||||
browserTrigger(inputElm, 'input');
|
||||
describe("IE placeholder input events", function() {
|
||||
//IE fires an input event whenever a placeholder visually changes, essentially treating it as a value
|
||||
//Events:
|
||||
// placeholder attribute change: *input*
|
||||
// focus (which visually removes the placeholder value): focusin focus *input*
|
||||
// blur (which visually creates the placeholder value): focusout *input* blur
|
||||
//However none of these occur if the placeholder is not visible at the time of the event.
|
||||
//These tests try simulate various scenerios which do/do-not fire the extra input event
|
||||
|
||||
it('should not dirty the model on an input event in response to a placeholder change', function() {
|
||||
compileInput('<input type="text" placeholder="Test" attr-capture ng-model="unsetValue" name="name" />');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
inputElm.attr('placeholder', 'Test Again');
|
||||
browserTrigger(inputElm, 'input');
|
||||
attrs.$set('placeholder', '');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
attrs.$set('placeholder', 'Test Again');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test Again');
|
||||
expect(inputElm).toBePristine();
|
||||
}
|
||||
}));
|
||||
|
||||
attrs.$set('placeholder', undefined);
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe(undefined);
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
});
|
||||
|
||||
it('should not dirty the model on an input event in response to a interpolated placeholder change', inject(function($rootScope) {
|
||||
compileInput('<input type="text" placeholder="{{ph}}" ng-model="unsetValue" name="name" />');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
$rootScope.ph = 1;
|
||||
$rootScope.$digest();
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
$rootScope.ph = "";
|
||||
$rootScope.$digest();
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should dirty the model on an input event while in focus even if the placeholder changes', inject(function($rootScope) {
|
||||
$rootScope.ph = 'Test';
|
||||
compileInput('<input type="text" ng-attr-placeholder="{{ph}}" ng-model="unsetValue" name="name" />');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusin');
|
||||
browserTrigger(inputElm, 'focus');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
$rootScope.ph = 'Test Again';
|
||||
$rootScope.$digest();
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should not dirty the model on an input event in response to a ng-attr-placeholder change', inject(function($rootScope) {
|
||||
compileInput('<input type="text" ng-attr-placeholder="{{ph}}" ng-model="unsetValue" name="name" />');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
$rootScope.ph = 1;
|
||||
$rootScope.$digest();
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
$rootScope.ph = "";
|
||||
$rootScope.$digest();
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should not dirty the model on an input event in response to a focus', inject(function($sniffer) {
|
||||
compileInput('<input type="text" placeholder="Test" ng-model="unsetValue" name="name" />');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusin');
|
||||
browserTrigger(inputElm, 'focus');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should not dirty the model on an input event in response to a blur', inject(function($sniffer) {
|
||||
compileInput('<input type="text" placeholder="Test" ng-model="unsetValue" name="name" />');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm.attr('placeholder')).toBe('Test');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusin');
|
||||
browserTrigger(inputElm, 'focus');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusout');
|
||||
msie && browserTrigger(inputElm, 'input');
|
||||
browserTrigger(inputElm, 'blur');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('foo');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should dirty the model on an input event if there is a placeholder and value', inject(function($rootScope) {
|
||||
$rootScope.name = 'foo';
|
||||
compileInput('<input type="text" placeholder="Test" ng-model="name" value="init" name="name" />');
|
||||
expect(inputElm.val()).toBe($rootScope.name);
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
changeInputValueTo('bar');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should dirty the model on an input event if there is a placeholder and value after focusing', inject(function($rootScope) {
|
||||
$rootScope.name = 'foo';
|
||||
compileInput('<input type="text" placeholder="Test" ng-model="name" value="init" name="name" />');
|
||||
expect(inputElm.val()).toBe($rootScope.name);
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusin');
|
||||
browserTrigger(inputElm, 'focus');
|
||||
changeInputValueTo('bar');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
|
||||
it('should dirty the model on an input event if there is a placeholder and value after bluring', inject(function($rootScope) {
|
||||
$rootScope.name = 'foo';
|
||||
compileInput('<input type="text" placeholder="Test" ng-model="name" value="init" name="name" />');
|
||||
expect(inputElm.val()).toBe($rootScope.name);
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusin');
|
||||
browserTrigger(inputElm, 'focus');
|
||||
expect(inputElm).toBePristine();
|
||||
|
||||
browserTrigger(inputElm, 'focusout');
|
||||
browserTrigger(inputElm, 'blur');
|
||||
changeInputValueTo('bar');
|
||||
expect(inputElm).toBeDirty();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
it('should interpolate input names', function() {
|
||||
|
||||
@@ -64,9 +64,10 @@ describe('$sniffer', function() {
|
||||
|
||||
it('should claim that IE9 doesn\'t have support for "oninput"', function() {
|
||||
// IE9 implementation is fubared, so it's better to pretend that it doesn't have the support
|
||||
// IE10+ implementation is fubared when mixed with placeholders
|
||||
mockDivElement = {oninput: noop};
|
||||
|
||||
expect($sniffer.hasEvent('input')).toBe((msie == 9) ? false : true);
|
||||
expect($sniffer.hasEvent('input')).toBe(!(msie && msie <= 11));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user