angular-viewportmise
Angular directive that executes a promise when it is in the viewport. It also adds some classes to DOM to know if it is loading, loaded on in an error status.
# How it works?
angular-viewportmise exports a directive called ``vpm``. This directive may be used like this:
```html
<!-- loader: Must be function returning a promise. -->
<!-- loadOnViewport: True to load on viewport otherwise false. -->
<div data-vlm
data-loader="::getTestData"
data-load-on-viewport="true">
</div>
```
angular-viewportmise will execute the method in two cases:
- If loadOnViewport === true: When it is inside the viewport
- If loadOnViewport === false: On load.
Moreover, angular-viewportmise will add 3 classes depending on the status of the directive:
- **vpm-loading**: When getData is set
- **vpm-loaded**: When getData success
- **vpm-error**: When getData fails
# Third party libs used
- angular-inview
HTML
<script src="https://rawgit.com/thenikso/angular-inview/master/angular-inview.js"></script>
<body data-ng-app="app">
<div data-ng-controller="mainCtrl">
<div data-ng-repeat="i in ::iterator">
<div data-ng-repeat="j in [0,1,2,3,4,0,1,2,3,4]">
<div data-ng-controller="testCtrl">
<!-- This directives will be executed inside viewport-->
<p data-vpm data-loader="::getTestData"
data-load-on-viewport="true"
data-ng-bind="::data">
</p>
</div>
</div>
</div>
<div data-ng-controller="testCtrl">
<!-- This directive will be executed without being on viewport-->
<p data-vpm data-loader="::getTestData"
data-ng-bind="::data">
</p>
</div>
</div>
</body>
CSS
/* Styles go here */
.vpm {
border: 5px solid grey;
margin: 5px;
height: 50px;
}
.vpm-loading {
background-color: yellow;
}
.vpm-error {
background-color: red;
}
.vpm-loaded {
background-color: green;
}
JavaScript
angular.module('app', [
'angular-viewportmise'
]);
angular.module('app')
.controller('mainCtrl', mainCtrl)
.controller('testCtrl', testCtrl);
/********************************************
* MAIN AND TEST CONTROLLERS (FOR TESTING)
*******************************************/
function mainCtrl($scope, $q, $timeout) {
var i = 50;
$scope.iterator = [];
while (i--) {
$scope.iterator.push(i);
}
$scope.getChannels = function() {
var deferred = $q.defer();
$timeout(function() {
$scope.channel = 'Test content';
deferred.resolve();
}, 500);
return deferred.promise;
};
}
function testCtrl($scope, $timeout, $q) {
$scope.getTestData = function() {
var deferred = $q.defer();
$timeout(function() {
$scope.data = 'Test data ' + new Date();
deferred.resolve();
}, 500);
return deferred.promise;
};
}
/********************************************
* ViewPortMise MODULE
*******************************************/
angular.module('angular-viewportmise', [
'angular-inview'
]);
angular.module('angular-viewportmise')
.directive('vpm', vpmDrct);
function vpmDrct() {
return {
template: '<div data-ng-transclude class="vpm" ' +
'data-in-view="load($inview)"></div>',
restrict: 'A',
scope: {
loadOnViewport: '=',
loader: '='
},
transclude: true,
replace: true,
link: function(scope, element) {
var clearGetDataWatcher;
/**
* Executes data loader and set classes depending on the status into
* the CSS.
*/
function _execLoader() {
if (scope.loader) {
scope.loader()
.then(function() {
element.removeClass('vpm-error');
element.addClass('vpm-loaded');
})
.catch(function() {
element.removeClass('vpm-loaded');
element.addClass('vpm-error');
})
.finally(function() {
...