In use cases where web applications utilize ng-repeat heavily and also rely on event triggers for each item in the collection, such as ng-click and the like, watchers become too numerous and may adversely affect performance when the number of items grow large.
To remedy this problem, an event delegation directive could handle the work. It is unfortunate that AngularJS does not support this as a built-in feature, but perhaps they might include it in a future release. Please review my code example for such a directive and point out any areas for improvement or if there's a better implementation.
Note: This example assumes that the view model (not shown) contains an array of items and a function called doSomething.
Update: Here is a working example in JSBin to illustrate its use.
Markup
<ul evt-delegate="doSomething(item)" evt-selector="li">
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
Code
(function () {
angular.module('myModule').directive('evtDelegate', ['$parse', delegateDirective]);
function delegateDirective($parse) {
return {
restrict: 'A',
scope: {
selector: '='
},
link: link
};
function link(scope, element, attributes) {
var selector = attributes.evtSelector,
expression = attributes.evtDelegate,
expressionHandler = $parse(expression);
element.on('click', function (e) {
var targetNode, targetScope;
targetNode = getTargetNode(element[0], e.target, selector);
if (targetNode) {
targetScope = angular.element(targetNode).scope();
targetScope.$apply(function () {
expressionHandler(targetScope);
});
}
});
}
function getTargetNode(parent, child, selector) {
if (!parent || !child) {
return null;
}
if (!selector) {
return child;
}
if (parent === child) {
// we traveresed all the way up to the parent node, so return
// null since the selector does not exist as a child
return null;
}
// we cannot trust that child.nodeName is uppercase,
// so we make sure it is before doing the comparison
if (child.nodeName.toUpperCase() === selector.toUpperCase()) {
return child;
}
return getTargetNode(parent, child.parentNode, selector);
}
}
})();
ng-clickbubble up to the ul level ? \$\endgroup\$ng-clickdirective on each<li>element. \$\endgroup\$