diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index e264db38e5b0..ea4d84f467f0 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -392,8 +392,21 @@ var inputType = { function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // 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 + var composing = false; + + element.on('compositionstart', function() { + composing = true; + }); + + element.on('compositionend', function() { + composing = false; + }); var listener = function() { + if (composing) return; var value = element.val(); // By default we will trim the value diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 3783c9edcec7..c6f5558ab9ec 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -454,6 +454,20 @@ describe('input', function() { expect(scope.name).toEqual('adam'); }); + it('should not update the model between "compositionstart" and "compositionend"', function() { + compileInput(''); + changeInputValueTo('a'); + expect(scope.name).toEqual('a'); + if (!(msie < 9)) { + browserTrigger(inputElm, 'compositionstart'); + changeInputValueTo('adam'); + expect(scope.name).toEqual('a'); + browserTrigger(inputElm, 'compositionend'); + } + changeInputValueTo('adam'); + expect(scope.name).toEqual('adam'); + }); + describe('"paste" and "cut" events', function() { beforeEach(function() { // Force browser to report a lack of an 'input' event