[AngularJS] Incorrect ng-mouseenter ng-mouseleave and Solution
Old version AngularJS (such as 1.1.3) has incorrect implementation of mouseenter and mouseleave directive:
Demo of incorrect implementation
See also this pull request (fix(jqLite): mouseenter/-leave should not trigger on child elements) on AngularJS Github repo for more details.
The following is correct implementation of mouseenter and mouseleave directive:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 'use strict'; /* Directives */ angular.module('pali.mouseEnterLeave', []). directive('mouseenter', [function() { return { restrict: 'A', link: function(scope, elm, attrs) { /** * check if element is targer or the parent of target * @param {DOM Element} target * @param {DOM Element} element * @return {boolean} Return true if element is target or the parent of target * else return false. */ function checkParent(target, element) { if (angular.isUndefined(target)) return false; // Chrome and Firefox use parentNode, while Opera use offsetParent while(target.parentNode) { if( target == element ) return true; target = target.parentNode; } while(target.offsetParent) { if( target == element ) return true; target = target.offsetParent; } return false; }; elm.bind('mouseover', function(e) { var evt = e || window.event; var targetElement = evt.target || evt.srcElement; // check if mouse moves inside the element, if yes, return. var relTarg = evt.relatedTarget || evt.fromElement; if (checkParent(relTarg, elm[0])) return; // https://gist.github.com/siongui/a8d9a9003772315e2cba if (scope.$root.$$phase) scope.$eval(attrs['mouseenter']); else scope.$apply(attrs['mouseenter']); }); } }; }]). directive('mouseleave', [function() { return { restrict: 'A', link: function(scope, elm, attrs) { /** * check if element is targer or the parent of target * @param {DOM Element} target * @param {DOM Element} element * @return {boolean} Return true if element is target or the parent of target * else return false. */ function checkParent(target, element) { if (angular.isUndefined(target)) return false; // Chrome and Firefox use parentNode, while Opera use offsetParent while(target.parentNode) { if( target == element ) return true; target = target.parentNode; } while(target.offsetParent) { if( target == element ) return true; target = target.offsetParent; } return false; }; elm.bind('mouseout', function(e) { var evt = e || window.event; var targetElement = evt.target || evt.srcElement; // check if mouse moves inside the element, if yes, return. var relTarg = evt.relatedTarget || evt.toElement; if (checkParent(relTarg, elm[0])) return; // https://gist.github.com/siongui/a8d9a9003772315e2cba if (scope.$root.$$phase) scope.$eval(attrs['mouseleave']); else scope.$apply(attrs['mouseleave']); }); } }; }]); |
The usage is the same as ngMouseenter and ngMouseleave, except the name changed to mouseenter and mouseleave. Also do not forget to include this module in your AngularJS application.