Fix directive + add example
This commit is contained in:
@@ -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);
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
})();
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Disable When Hidden Example</title>
|
||||
|
||||
|
||||
<style>
|
||||
.item {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: #F2D888;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: fixed;
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body ng-app='app'>
|
||||
|
||||
<div ng-controller='listCtrl as list'>
|
||||
|
||||
<button class='button' ng-click='list.countWatchers()'>Console.log watchers</button>
|
||||
|
||||
<div disable-when-hidden>
|
||||
<div ng-repeat="item in list.array" class="item" dwh-element>
|
||||
<p ng-bind='item.title'></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JS files -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
|
||||
<script src="example/main.js"></script>
|
||||
<script src="src/disableWhenHidden.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
Executable
+148
@@ -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);
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user