Skip to content

Commit 6f77552

Browse files
committed
fix(ngEventDirs): blur and focus use $evalAysnc to prevent inprog errors
Fixes angular#5945 Closes angular#5402
1 parent 876df04 commit 6f77552

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

src/ng/directive/ngEventDirs.js

+27-2
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131
</example>
3232
*/
3333
/*
34-
* A directive that allows creation of custom onclick handlers that are defined as angular
34+
* A directive that allows creation of custom event handlers that are defined as angular
3535
* expressions and are compiled and executed within the current scope.
3636
*
3737
* Events that are handled via these handler are always configured not to propagate further.
3838
*/
3939
var ngEventDirectives = {};
4040
forEach(
41-
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
41+
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit copy cut paste'.split(' '),
4242
function(name) {
4343
var directiveName = directiveNormalize('ng-' + name);
4444
ngEventDirectives[directiveName] = ['$parse', function($parse) {
@@ -58,6 +58,31 @@ forEach(
5858
}
5959
);
6060

61+
/*
62+
* Focus and blur need to use $evalAsync to prevent $rootScope.inprog errors when focus() / blur() are triggered
63+
* during a digest
64+
*/
65+
forEach(
66+
'focus blur'.split(' '),
67+
function(name) {
68+
var directiveName = directiveNormalize('ng-' + name);
69+
ngEventDirectives[directiveName] = ['$parse', function($parse) {
70+
return {
71+
compile: function($element, attr) {
72+
var fn = $parse(attr[directiveName]);
73+
return function(scope, element, attr) {
74+
element.on(lowercase(name), function(event) {
75+
scope.$evalAsync(function() {
76+
fn(scope, {$event:event});
77+
});
78+
});
79+
};
80+
}
81+
};
82+
}];
83+
}
84+
);
85+
6186
/**
6287
* @ngdoc directive
6388
* @name ngDblclick

test/ng/directive/ngEventDirsSpec.js

+34
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,38 @@ describe('event directives', function() {
3939
expect($rootScope.formSubmitted).toEqual('foo');
4040
}));
4141
});
42+
43+
describe('ngBlur', function() {
44+
iit('should get called when ngKeydown triggers blur', inject(function($rootScope, $compile) {
45+
$rootScope.blur = function() {
46+
browserTrigger(element, 'blur');
47+
}
48+
49+
element = $compile('<input type="text" ng-blur="blurred = true" ng-keydown="blur()" />')($rootScope);
50+
51+
$rootScope.$digest();
52+
expect($rootScope.blurred).not.toBeDefined();
53+
54+
browserTrigger(element, 'keydown');
55+
expect($rootScope.blurred).toEqual(true);
56+
}));
57+
});
58+
59+
describe('ngFocus', function() {
60+
iit('should get called when ngClick triggers focus', inject(function($rootScope, $compile) {
61+
$rootScope.focus = function() {
62+
browserTrigger(element.children()[0], 'focus');
63+
}
64+
65+
element = $compile('<div><input type="text" ng-focus="focused = true" />' +
66+
'<button type="button" ng-click="focus()"></button></div>')($rootScope);
67+
68+
$rootScope.$digest();
69+
expect($rootScope.focused).not.toBeDefined();
70+
71+
browserTrigger(element.children()[1], 'click');
72+
expect($rootScope.focused).toEqual(true);
73+
}));
74+
});
75+
4276
});

0 commit comments

Comments
 (0)