Skip to content

Instantly share code, notes, and snippets.

@supertinou
Created June 16, 2016 18:29
Show Gist options
  • Save supertinou/5bc8bcfc731da439a09206d4fffacc76 to your computer and use it in GitHub Desktop.
Save supertinou/5bc8bcfc731da439a09206d4fffacc76 to your computer and use it in GitHub Desktop.
An AngularJS directive that allows to be aware when a ng-repeat has finish being rendered.
// @author: @BenNadel
// Source : http://www.bennadel.com/blog/2592-hooking-into-the-complete-event-of-an-ngrepeat-loop-in-angularjs.htm
angular.module('app')
.directive("repeatComplete",
function( $rootScope ) {
// Because we can have multiple ng-repeat directives in
// the same container, we need a way to differentiate
// the different sets of elements. We'll add a unique ID
// to each set.
var uuid = 0;
// I compile the DOM node before it is linked by the
// ng-repeat directive.
function compile( tElement, tAttributes ) {
// Get the unique ID that we'll be using for this
// particular instance of the directive.
var id = ++uuid;
// Add the unique ID so we know how to query for
// DOM elements during the digests.
tElement.attr( "repeat-complete-id", id );
// Since this directive doesn't have a linking phase,
// remove it from the DOM node.
tElement.removeAttr( "repeat-complete" );
// Keep track of the expression we're going to
// invoke once the ng-repeat has finished
// rendering.
var completeExpression = tAttributes.repeatComplete;
// Get the element that contains the list. We'll
// use this element as the launch point for our
// DOM search query.
var parent = tElement.parent();
// Get the scope associated with the parent - we
// want to get as close to the ngRepeat so that our
// watcher will automatically unbind as soon as the
// parent scope is destroyed.
var parentScope = ( parent.scope() || $rootScope );
// Since we are outside of the ng-repeat directive,
// we'll have to check the state of the DOM during
// each $digest phase; BUT, we only need to do this
// once, so save a referene to the un-watcher.
var unbindWatcher = parentScope.$watch(
function() {
// Now that we're in a digest, check to see
// if there are any ngRepeat items being
// rendered. Since we want to know when the
// list has completed, we only need the last
// one we can find.
var lastItem = parent.children( "*[ repeat-complete-id = '" + id + "' ]:last" );
// If no items have been rendered yet, stop.
if ( ! lastItem.length ) {
return;
}
// Get the local ng-repeat scope for the item.
var itemScope = lastItem.scope();
// If the item is the "last" item as defined
// by the ng-repeat directive, then we know
// that the ng-repeat directive has finished
// rendering its list (for the first time).
if ( itemScope.$last ) {
// Stop watching for changes - we only
// care about the first complete rendering.
//unbindWatcher();
// Invoke the callback.
itemScope.$eval( completeExpression );
}
}
);
}
// Return the directive configuration. It's important
// that this compiles before the ngRepeat directive
// compiles the DOM node.
return({
compile: compile,
priority: 1001,
restrict: "A"
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment