Skip to content

Commit 1147f21

Browse files
mgolIgorMinar
authored andcommitted
fix(input): prevent double $digest when using jQuery trigger.
If an event was performed natively, jQuery sets the isTrigger property. When triggering event manually, the field is not present. Manually triggered events are performed synchronously which causes the "$digest already in progress" error. Closes angular#5293
1 parent bddd46c commit 1147f21

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

src/ng/directive/input.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
407407
});
408408
}
409409

410-
var listener = function() {
410+
var listener = function(ev) {
411411
if (composing) return;
412412
var value = element.val();
413413

@@ -419,9 +419,17 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
419419
}
420420

421421
if (ctrl.$viewValue !== value) {
422-
scope.$apply(function() {
422+
// If an event was performed natively, jQuery sets the isTrigger property.
423+
// When triggering event manually, the field is not present. Manually
424+
// triggered events are performed synchronously which causes the "$digest
425+
// already in progress" error.
426+
if (ev && ev.isTrigger) {
423427
ctrl.$setViewValue(value);
424-
});
428+
} else {
429+
scope.$apply(function() {
430+
ctrl.$setViewValue(value);
431+
});
432+
}
425433
}
426434
};
427435

src/ngScenario/Scenario.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ function callerFile(offset) {
239239
* To work around this we instead use our own handler that fires a real event.
240240
*/
241241
(function(fn){
242-
var parentTrigger = fn.trigger;
242+
// We need a handle to the original trigger function for input tests.
243+
var parentTrigger = fn._originalTrigger = fn.trigger;
243244
fn.trigger = function(type) {
244245
if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
245246
var processDefaults = [];

test/ng/directive/inputSpec.js

+17
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,23 @@ describe('input', function() {
533533
'event so that form auto complete works',function() {
534534
assertBrowserSupportsChangeEvent(true);
535535
});
536+
537+
if (!_jqLiteMode) {
538+
it('should not cause the double $digest when triggering an event using jQuery', function() {
539+
$sniffer.hasEvent = function(eventName) {
540+
return eventName !== 'input';
541+
};
542+
543+
compileInput('<input type="text" ng-model="name" name="alias" ng-change="change()" />');
544+
545+
scope.field = 'fake field';
546+
scope.$watch('field', function() {
547+
// We need to use _originalTrigger since trigger is modified by Angular Scenario.
548+
inputElm._originalTrigger('change');
549+
});
550+
scope.$apply();
551+
});
552+
}
536553
});
537554

538555
describe('"paste" and "cut" events', function() {

0 commit comments

Comments
 (0)