Reputation: 19197
I am using code like this to create an endless scroll effect in AngularJS. I tried to refactor some of the code, by moving the content of the scrollable container (in this case the ul
) to a seperate html file, and then use a ng-view to load the content.
After this is done the scope.$apply(attr.whenScrolled);
doesn't have any effect. The loadMore()
method is simply not called anymore.
Have I changed something about the scope after moving the ul-content to a seperate file, and loading it in dynamically?
Update: Here is the code:
App.directive('whenScrolled', function() {
return function(scope, element, attr) {
var raw = element[0];
// binding on element doesn't work so this is a temp fix
$(document).bind('scroll', function() {
var scrollPercentage = (($(window).scrollTop() + $(window).height()) / $(document).height()) * 100;
if(scrollPercentage > 75 && !scope.in_progress && !scope.is_reached_end)
{
console.log('test')
scope.$apply(attr.whenScrolled);
}
});
};
});
App.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/', {
templateUrl: 'views/offers.html',
controller: 'OffersCntl'
});
}]);
The view:
<div class="tileContainer" ng-controller="OffersCntl">
<h2>Something very important :)</h2>
<div id="tiles" class="tiles" when-scrolled="loadMore()">
<div ng-view></div>
</div>
</div>
I have a rather fat controller, which I don't want to polute the post with. It basically have a scope.loadMore method.
Upvotes: 4
Views: 4230
Reputation: 3394
This directive uses the scroll offset to give elasticity to the component and not limit it at a fixed height:
app.directive('whenScrolled', function($window, $timeout) {
return {
restrict: "A",
link: function(scope, element, attr) {
// bind the digest cycle to be triggered by the scroll event
// when it exceeds a threshold
angular.element($window).bind('scroll', function() {
var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
var scrollY = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
var iScroll = element.prop('offsetTop') + element.prop('offsetHeight');
var iScrooling = scrollY + ( this.screen.height * 0.9 );
//console.log(iScrooling+'/'+iScroll);
if ( iScrooling >= iScroll ) {
angular.element($window)[0].requestAnimationFrame(function(){
// invoke the function passed into the 'whenScrolled' attribute
scope.$apply(attr.whenScrolled);
})
}
});
}
}
});
Your HTML:
<div class="tileContainer" ng-controller="OffersCntl">
<h2>Something very important :)</h2>
<div id="tiles" class="tiles" when-scrolled="loadMore()">
<div ng-repeat="item in items">
{{ item.id }}
</div>
</div>
</div>
The Controller, you can replace this with a request Ajax
$scope.items = [];
var counter = 0;
$scope.loadMore = function() {
for (var i = 0; i < 5; i++) {
$scope.items.push({id: counter});
counter += 10;
}
};
$scope.loadMore();
If you need support to old browsers, you can add this function:
//requestAnimationFrame for old browsers
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
Upvotes: 0
Reputation: 16261
Use ng-include
instead of ng-view
.
http://jsfiddle.net/pvtpenguin/U7Bz9/540/
For example, in your view:
<div class="tileContainer" ng-controller="OffersCntl">
<h2>Something very important :)</h2>
<div id="tiles" class="tiles" when-scrolled="loadMore()">
<div ng-include src="'offer.html'"></div>
</div>
</div>
Upvotes: 5