Quickly put together lazy load of a JSON feed using AngularJS.
A Pen by Zachary Wills on CodePen.
Quickly put together lazy load of a JSON feed using AngularJS.
A Pen by Zachary Wills on CodePen.
| <div ng-app="myApp"> | |
| <div class="[ press-releases ]" ng-controller="PressReleaseController"> | |
| <h1>AJAX Lazy Load using AngularJS</h1> | |
| <p>When the content area nears the end of the browser, another <strong>{{limit}}</strong> items will load in.</p> | |
| <p>There are currently <strong>{{releases.length}}</strong> items loaded.</p> | |
| <ul infinite-scroll="loadItems()" infinite-scroll-distance="10"> | |
| <li class="[ press-release ]" ng-repeat="release in releases | orderBy: 'published': true"> | |
| <h2 class="[ press-release__title ]">{{release.title}}</h2> | |
| <div class="[ press-release__meta ]">{{release.published}}</div> | |
| </li><!-- .press-release --> | |
| </ul><!-- .press-release --> | |
| <div class="[ press-releases__info ]" ng-hide="more_items"> | |
| There are no more items to load! I will not process any more AJAX requests. | |
| </div><!-- .press-releases__info --> | |
| </div><!-- .press-releases --> | |
| </div> |
| /** | |
| * Establish our Angular App | |
| */ | |
| var myApp = angular.module('myApp', ['infinite-scroll']); | |
| // var to use as a flag to prevent http requests from happening when one is already occuring | |
| var infinite_loading = false; | |
| /* | |
| * Create custom factory for the dynamic loading | |
| */ | |
| myApp.factory('PressReleases', function($http) { | |
| /* | |
| * load | |
| * Load in the press releases | |
| */ | |
| var load = function(full_url, last_loaded_url) { | |
| infinite_loading = true; | |
| return $http({method:"GET", url: full_url}).then(function(result){ | |
| return result.data; | |
| }); | |
| }; | |
| return { load: load }; | |
| }); | |
| /** | |
| * PressReleaseController | |
| */ | |
| myApp.controller('PressReleaseController', ['$scope', '$http', 'PressReleases', function($scope, $http, PressReleases) { | |
| // establish vars | |
| $scope.releases = []; | |
| $scope.limit = 10; | |
| $scope.offset = 0; | |
| $scope.more_items = true; // flag to see if we hit the end of the json feed | |
| /** | |
| * loadMore | |
| * Adjust the offset using the limit to add X number of | |
| * items to the list | |
| */ | |
| $scope.loadItems = function(){ | |
| // make sure there are more items to load | |
| if($scope.more_items == true && infinite_loading == false) { | |
| var url = 'http://www.stellarbiotechnologies.com/media/press-releases/json/?limit=' + $scope.limit + '&offset=' + $scope.offset; | |
| // load the press releases | |
| var getPressReleases = PressReleases.load(url, $scope.last_loaded_url); | |
| // this is only run after $http completes | |
| getPressReleases.then(function(result) { | |
| // we finished loading, set the flag back | |
| infinite_loading = false; | |
| // check if there were any news items in the latest feed | |
| if(result.news.length == 0) { | |
| $scope.more_items = false; | |
| } else { | |
| // result news | |
| $scope.releases = $scope.releases.concat(result.news); | |
| } | |
| // increment the offset for next time loadMore() is called | |
| $scope.offset = $scope.limit + $scope.offset; | |
| // update the last loaded url | |
| $scope.last_loaded_url = url; | |
| }); | |
| } | |
| } | |
| }]); | |
| /** | |
| * ng-infinite-scroll - v1.2.0 - 2014-12-02 | |
| */ | |
| var mod;mod=angular.module("infinite-scroll",[]),mod.value("THROTTLE_MILLISECONDS",null),mod.directive("infiniteScroll",["$rootScope","$window","$interval","THROTTLE_MILLISECONDS",function(a,b,c,d){return{scope:{infiniteScroll:"&",infiniteScrollContainer:"=",infiniteScrollDistance:"=",infiniteScrollDisabled:"=",infiniteScrollUseDocumentBottom:"="},link:function(e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x;return x=angular.element(b),t=null,u=null,i=null,j=null,q=!0,w=!1,p=function(a){return a=a[0]||a,isNaN(a.offsetHeight)?a.document.documentElement.clientHeight:a.offsetHeight},r=function(a){return a[0].getBoundingClientRect&&!a.css("none")?a[0].getBoundingClientRect().top+s(a):void 0},s=function(a){return a=a[0]||a,isNaN(window.pageYOffset)?a.document.documentElement.scrollTop:a.ownerDocument.defaultView.pageYOffset},o=function(){var b,c,d,g,h;return j===x?(b=p(j)+s(j[0].document.documentElement),d=r(f)+p(f)):(b=p(j),c=0,void 0!==r(j)&&(c=r(j)),d=r(f)-c+p(f)),w&&(d=p((f[0].ownerDocument||f[0].document).documentElement)),g=d-b,h=g<=p(j)*t+1,h?(i=!0,u?e.$$phase||a.$$phase?e.infiniteScroll():e.$apply(e.infiniteScroll):void 0):i=!1},v=function(a,b){var d,e,f;return f=null,e=0,d=function(){var b;return e=(new Date).getTime(),c.cancel(f),f=null,a.call(),b=null},function(){var g,h;return g=(new Date).getTime(),h=b-(g-e),0>=h?(clearTimeout(f),c.cancel(f),f=null,e=g,a.call()):f?void 0:f=c(d,h,1)}},null!=d&&(o=v(o,d)),e.$on("$destroy",function(){return j.unbind("scroll",o)}),m=function(a){return t=parseFloat(a)||0},e.$watch("infiniteScrollDistance",m),m(e.infiniteScrollDistance),l=function(a){return u=!a,u&&i?(i=!1,o()):void 0},e.$watch("infiniteScrollDisabled",l),l(e.infiniteScrollDisabled),n=function(a){return w=a},e.$watch("infiniteScrollUseDocumentBottom",n),n(e.infiniteScrollUseDocumentBottom),h=function(a){return null!=j&&j.unbind("scroll",o),j=a,null!=a?j.bind("scroll",o):void 0},h(x),k=function(a){if(null!=a&&0!==a.length){if(a instanceof HTMLElement?a=angular.element(a):"function"==typeof a.append?a=angular.element(a[a.length-1]):"string"==typeof a&&(a=angular.element(document.querySelector(a))),null!=a)return h(a);throw new Exception("invalid infinite-scroll-container attribute.")}},e.$watch("infiniteScrollContainer",k),k(e.infiniteScrollContainer||[]),null!=g.infiniteScrollParent&&h(angular.element(f.parent())),null!=g.infiniteScrollImmediateCheck&&(q=e.$eval(g.infiniteScrollImmediateCheck)),c(function(){return q?o():void 0},0,1)}}}]); |
| // vars | |
| $spacing-base: 24px; | |
| // reset | |
| * { | |
| box-sizing: border-box; | |
| -moz-box-sizing: border-box; | |
| -webkit-box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| // styles | |
| body { | |
| background: #043958; | |
| padding-top: $spacing-base; | |
| line-height: 25px; | |
| } | |
| ul { | |
| list-style-type: none; | |
| } | |
| h1, h2 { | |
| line-height: 1.3em; | |
| } | |
| p { | |
| margin-bottom: $spacing-base; | |
| } | |
| .site-header { | |
| background: white; | |
| padding: $spacing-base; | |
| } | |
| .press-releases { | |
| margin: auto; | |
| width: 90%; | |
| padding: $spacing-base; | |
| margin-bottom: $spacing-base; | |
| background: white; | |
| } | |
| .press-release { | |
| padding: $spacing-base; | |
| margin-bottom: $spacing-base; | |
| background: #eee; | |
| } | |
| .press-releases__info { | |
| padding: $spacing-base; | |
| color: white; | |
| background: #0262b5; | |
| } |