From 5ec9e6d84d119c5b6b90c83b2dc6e6e8190aec8b Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Thu, 21 Mar 2013 18:07:49 +1100 Subject: [PATCH] fix(ngModel): use paste/cut events in IE to support context menu In IE the model is not updated when the input value is modified using the context menu, e.g. pasting from the clipboard, or cutting all or part of the current value. To capture these changes, we bind to the proprietary 'paste' and 'cut' events. Closes #1462 --- src/ng/directive/input.js | 21 +++++++++++++++------ test/ng/directive/inputSpec.js | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index aaabd1033398..797600075537 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -413,6 +413,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { } else { var timeout; + var deferListener = function() { + if (!timeout) { + timeout = $browser.defer(function() { + listener(); + timeout = null; + }); + } + }; + element.bind('keydown', function(event) { var key = event.keyCode; @@ -420,16 +429,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { // command modifiers arrows if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; - if (!timeout) { - timeout = $browser.defer(function() { - listener(); - timeout = null; - }); - } + deferListener(); }); // if user paste into input using mouse, we need "change" event to catch it element.bind('change', listener); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.bind('paste cut', deferListener); + } } diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 4dcb79a38d12..e1f24afd30f9 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -309,7 +309,7 @@ describe('ngModel', function() { describe('input', function() { - var formElm, inputElm, scope, $compile, changeInputValueTo; + var formElm, inputElm, scope, $compile, $sniffer, $browser, changeInputValueTo; function compileInput(inputHtml) { inputElm = jqLite(inputHtml); @@ -318,7 +318,9 @@ describe('input', function() { $compile(formElm)(scope); } - beforeEach(inject(function($injector, $sniffer) { + beforeEach(inject(function($injector, _$sniffer_, _$browser_) { + $sniffer = _$sniffer_; + $browser = _$browser_; $compile = $injector.get('$compile'); scope = $injector.get('$rootScope'); @@ -385,6 +387,34 @@ describe('input', function() { expect(scope.name).toEqual('adam'); }); + describe('"paste" and "cut" events', function() { + beforeEach(function() { + // Force browser to report a lack of an 'input' event + $sniffer.hasEvent = function(eventName) { + return eventName !== 'input'; + }; + }); + + it('should update the model on "paste" event', function() { + compileInput(''); + + inputElm.val('mark'); + browserTrigger(inputElm, 'paste'); + $browser.defer.flush(); + expect(scope.name).toEqual('mark'); + }); + + it('should update the model on "cut" event', function() { + compileInput(''); + + inputElm.val('john'); + browserTrigger(inputElm, 'cut'); + $browser.defer.flush(); + expect(scope.name).toEqual('john'); + }); + + }); + it('should update the model and trim the value', function() { compileInput('');