From dbbb4b65171e462a866258a3eddb7621b2c69d82 Mon Sep 17 00:00:00 2001 From: Mimu Date: Sun, 8 Mar 2015 17:47:34 +0100 Subject: [PATCH] Fix directive + add example --- disableWhenHidden.js | 128 --------------------------------- example/main.js | 50 +++++++++++++ index.html | 48 +++++++++++++ src/disableWhenHidden.js | 148 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+), 128 deletions(-) delete mode 100755 disableWhenHidden.js create mode 100644 example/main.js create mode 100644 index.html create mode 100755 src/disableWhenHidden.js diff --git a/disableWhenHidden.js b/disableWhenHidden.js deleted file mode 100755 index a2561ca..0000000 --- a/disableWhenHidden.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Created by Brice on 01/10/2014. - */ - - -/** - * Listen to the scroll event and broadcast an event to disable / enable the watchers of the "dwhElements" - */ -webassadorsApp.directive('disableWhenHidden', ['$timeout', '$compile', 'CommonTools', function ($timeout, $compile, CommonTools) { - 'use strict'; - return { - restrict: 'A', - link: function (scope) { - var checkElements = CommonTools.debounce(function () { - scope.$broadcast('dwhCheckElements'); - }, 250); - // Hide / Show posts every time the user scrolls - document.addEventListener('scroll', checkElements); - } - }; -}]); - -/** - * When out of sight, we empty the watchers, when back up we bring them back ! - */ -webassadorsApp.directive('dwhElement', function () { - 'use strict'; - return { - restrict: 'A', - link: function (scope, element) { - var el = element[0]; - var m = 1000; // Range of "errors" outside the viewport - var wArray; // Array to store all the watchers - var isHidden = false; // Used to prevent useless computation - - /** - * Store all the watchers and empty it so we never go crazy - */ - var disableWatchers = function () { - // Hide element - wArray = []; - leaveHimToDie(el); - isHidden = true; - }; - - /** - * Bring the watchers back - */ - var enableWatchers = function () { - bringHimBack(el); - isHidden = false; - }; - - // Listen to scroll events - scope.$on('dwhCheckElements', function () { - var coordinates = el.getBoundingClientRect(); - if (coordinates.bottom > 0 - m && coordinates.top < window.innerHeight + m) { - if (isHidden) { - enableWatchers(); - } - } else if (!isHidden) { - disableWatchers(); - } - }); - - /** - * Goes through every child elements and store the watchers if they exist - * Then empty every array to remove them - * @param elem - */ - var leaveHimToDie = function (elem) { - elem = angular.element(elem); - var i = 0; - - function getElemWatchers(element) { - wArray[i] = []; - wArray[i][0] = getWatchersFromScope(element.data().$isolateScope); - wArray[i][1] = getWatchersFromScope(element.data().$scope); - - angular.forEach(element.children(), function (childElement) { - i++; - getElemWatchers(angular.element(childElement)); - }); - } - - function getWatchersFromScope(scope) { - if (scope) { - var tmp = scope.$$watchers || []; - scope.$$watchers = []; - return tmp; - } else { - return []; - } - } - - getElemWatchers(elem); - }; - - /** - * Go through every child elements and restore the watchers from the array we stored with "leaveHimToDie" - * @param elem - */ - var bringHimBack = function (elem) { - elem = angular.element(elem); - var i = 0; - - function setElemWatchers(element) { - setWatchersFromScope(element.data().$isolateScope, 0); - setWatchersFromScope(element.data().$scope, 1); - - angular.forEach(element.children(), function (childElement) { - i++; - setElemWatchers(angular.element(childElement)); - }); - } - - function setWatchersFromScope(scope, n) { - if (scope) { - scope.$$watchers = wArray[i][n]; - } - } - - // Start the loop - setElemWatchers(elem); - }; - } - }; -}); \ No newline at end of file diff --git a/example/main.js b/example/main.js new file mode 100644 index 0000000..c4e3a3c --- /dev/null +++ b/example/main.js @@ -0,0 +1,50 @@ +(function() { + 'use strict'; + + var app = angular.module('app', []); + + app.controller('listCtrl', function() { + + var arr = []; + + for (var i=0; i<1000; i++) { + arr[i] = { + title: 'Element ' + i.toString() + } + } + + this.array = arr; + + this.countWatchers = function() { + var root = angular.element(document.getElementsByTagName('body')); + + var watchers = []; + + var f = function (element) { + angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) { + if (element.data() && element.data().hasOwnProperty(scopeProperty)) { + angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) { + watchers.push(watcher); + }); + } + }); + + angular.forEach(element.children(), function (childElement) { + f(angular.element(childElement)); + }); + }; + + f(root); + + // Remove duplicate watchers + var watchersWithoutDuplicates = []; + angular.forEach(watchers, function(item) { + if(watchersWithoutDuplicates.indexOf(item) < 0) { + watchersWithoutDuplicates.push(item); + } + }); + + console.log(watchersWithoutDuplicates.length); + } + }); +})(); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..6cdb57e --- /dev/null +++ b/index.html @@ -0,0 +1,48 @@ + + + Disable When Hidden Example + + + + + + + + + +
+ + + +
+
+

+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/src/disableWhenHidden.js b/src/disableWhenHidden.js new file mode 100755 index 0000000..304ef0e --- /dev/null +++ b/src/disableWhenHidden.js @@ -0,0 +1,148 @@ +(function() { + 'use strict'; + + var app = angular.module('app'); + + /** + * First directive, placed on the parent element + * Broadcast an event to every relevant child elements every time the user scroll to update the $$watchers situation + */ + app.directive('disableWhenHidden', function() { + return { + restrict: 'A', + + link: function(scope) { + + function debounce(fn, delay) { + var timer = null; + return function () { + var context = this, args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + } + + + var checkElements = debounce(function() { + scope.$broadcast('dwhCheckElements'); + }, 250); + + document.addEventListener('scroll', checkElements); + } + }; + }); + + + /** + * + */ + app.directive('dwhElement', function() { + return { + restrict: 'A', + + link: function(scope, element) { + + var m = 1000; // Range of "errors" outside the viewport + var wArray = []; // Array to store all the watchers + var isHidden = false; // Used to prevent useless computation + + /** + * Store every watchers related to the element + * Remove them from the element + */ + var disableWatchers = function () { + wArray.length = 0; + leaveHimToDie(element); + isHidden = true; + }; + + /** + * Put back every watchers from the storage array + */ + var enableWatchers = function () { + bringHimBack(element); + isHidden = false; + }; + + /** + * Listener to know when to enable/disable watchers + */ + scope.$on('dwhCheckElements', function () { + var coordinates = element[0].getBoundingClientRect(); + if (coordinates.bottom > 0 - m && coordinates.top < window.innerHeight + m) { + if (isHidden) { + enableWatchers(); + } + } else if (!isHidden) { + disableWatchers(); + } + }); + + + /*--- Watchers's dance ---*/ + + /** + * Goes through every child elements and store the watchers if they exist + * Then empty every array to disable them + * @param elem + */ + var leaveHimToDie = function (elem) { + var i = 0; + + function getElemWatchers(element) { + wArray[i] = []; + wArray[i][0] = getWatchersFromScope(element.data().$isolateScope); + wArray[i][1] = getWatchersFromScope(element.data().$scope); + + angular.forEach(element.children(), function (childElement) { + i++; + getElemWatchers(angular.element(childElement)); + }); + } + + function getWatchersFromScope(scope) { + if (scope) { + var tmp = scope.$$watchers || []; + scope.$$watchers = []; + return tmp; + } else { + return []; + } + } + + getElemWatchers(elem); + }; + + /** + * Go through every child elements and restore the watchers from the array we stored with "leaveHimToDie" + * @param elem + */ + var bringHimBack = function (elem) { + var i = 0; + + function setElemWatchers(element) { + setWatchersFromScope(element.data().$isolateScope, 0); + setWatchersFromScope(element.data().$scope, 1); + + angular.forEach(element.children(), function (childElement) { + i++; + setElemWatchers(angular.element(childElement)); + }); + } + + function setWatchersFromScope(scope, n) { + if (scope) { + scope.$$watchers = wArray[i][n]; + } + } + + // Start the loop + setElemWatchers(elem); + }; + } + }; + }); + +})(); \ No newline at end of file