Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!doctype html>
- <html ng-app="Demo">
- <head>
- <meta charset="utf-8" />
- <title>
- Hooking Into The ngRepeat Completion Event In AngularJS
- </title>
- <style type="text/css">
- a[ ng-click ] {
- cursor: pointer ;
- text-decoration: underline ;
- }
- </style>
- </head>
- <body ng-controller="AppController">
- <h1>
- Hooking Into The ngRepeat Completion Event In AngularJS
- </h1>
- <h3>
- Friends
- </h3>
- <ul>
- <!--
- When the ngRepeat finishes its first round of rendering,
- we're going to invoke the doSomething() callback.
- -->
- <li
- ng-repeat="friend in friends"
- repeat-complete="doSomething( $index )">
- {{ friend.name }}
- </li>
- </ul>
- <p>
- <a ng-click="addFriend()">Add Friend</a>
- -
- <em>This will NOT trigger any more "complete" events</em>.
- </p>
- <h3>
- Enemies
- </h3>
- <ul>
- <!--
- When the ngRepeat finishes its first round of rendering,
- we're going to invoke the doSomething() callback.
- -->
- <li
- ng-repeat="enemy in enemies"
- repeat-complete="doSomething( $index )">
- {{ enemy.name }}
- </li>
- </ul>
- <p>
- <a ng-click="addEnemy()">Add Enemy</a>
- -
- <em>This WILL trigger one more "complete" event</em>.
- </p>
- <!-- Load scripts. -->
- <script type="text/javascript" src="../../vendor/jquery/jquery-2.0.3.min.js"></script>
- <script type="text/javascript" src="../../vendor/angularjs/angular-1.2.min.js"></script>
- <script type="text/javascript">
- // Create an application module for our demo.
- var app = angular.module( "Demo", [] );
- // -------------------------------------------------- //
- // -------------------------------------------------- //
- // I control the root of the application.
- app.controller(
- "AppController",
- function( $scope ) {
- // Define the collection of friends to render.
- $scope.friends = [
- {
- name: "Sarah"
- },
- {
- name: "Joanna"
- },
- {
- name: "Tricia"
- }
- ];
- // Define the collection of enemies to render. This
- // collection will start out empty in order to demonstrate
- // that this approach requires at least ONE element to
- // render.
- $scope.enemies = [];
- // ---
- // PUBLIC METHODS.
- // ---
- // I add a new enemty to the collection.
- $scope.addEnemy = function() {
- $scope.enemies.push({
- name: "Banana"
- });
- }
- // I add a new friend to the collection.
- $scope.addFriend = function() {
- $scope.friends.push({
- name: "Anna"
- });
- }
- // I am the callback handler for the ngRepeat completion.
- $scope.doSomething = function( index ) {
- console.log( "ngRepeat completed (" + index + ")!" );
- };
- }
- );
- // -------------------------------------------------- //
- // -------------------------------------------------- //
- // I invoke the given expression when associated ngRepeat loop
- // has finished its first round of rendering.
- 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() {
- console.info( "Digest running." );
- // 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"
- });
- }
- );
- </script>
- </body>
- </html>
Add Comment
Please, Sign In to add comment