Fix directive + add example

This commit is contained in:
Mimu
2015-03-08 17:47:34 +01:00
parent ee7c5d688b
commit dbbb4b6517
4 changed files with 246 additions and 128 deletions
-128
View File
@@ -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);
};
}
};
});
+50
View File
@@ -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
View File
@@ -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>
+148
View File
@@ -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);
};
}
};
});
})();