-
-
Save CMCDragonkai/8055961 to your computer and use it in GitHub Desktop.
app.directive('asyncAnchor', [ | |
'$location', | |
'$anchorScroll', | |
'$timeout', | |
function($location, $anchorScroll, $timeout){ | |
return { | |
link: function(scope, element, attributes){ | |
var id = attributes.asyncAnchor || attributes.id || attributes.name; | |
var delay = attributes.asyncAnchorDelay; | |
var eventName = attributes.asyncAnchorEvent; | |
var firstTimeScrolling = true; | |
var scrollToHash = function(hash){ | |
if(id && hash && id === hash){ | |
if(delay && firstTimeScrolling){ | |
$timeout(function(){ | |
$anchorScroll(); | |
}, delay); | |
}else{ | |
$anchorScroll(); | |
} | |
//only run the delay the first time this scrolling function executes | |
//if the hash didn't match, then this function didn't execute! | |
firstTimeScrolling = false; | |
} | |
}; | |
//listen for a custom event, useful if you're waiting on something else to be fully loaded as well | |
if(eventName){ | |
scope.$on(eventName, function(){ | |
scrollToHash($location.hash()); | |
}); | |
} | |
//hash may be asynchronously changed, the directive may load before the hash is added | |
scope.$watch(function(){ | |
return $location.hash(); | |
}, function(hash){ | |
scrollToHash(hash); | |
}); | |
} | |
}; | |
} | |
]); |
Updated to make the delay only occur on the first time the hash scrolling executes. It shouldn't delay every time. The purpose of the delay was to allow other things to occur before the first time you scroll. No point in delaying the scroll every time.
If anyone stumbles across this at a later point: AngularJS has this built in.
Add autoscroll="true" on your ng-view element and the page will scroll for you when the page loads (even with async content - I resolve that in the routing if it maters)
@mlenser of course it matters. If you don't load your data using route resolve and load view model when controller i instatiated, then it's already too late for the $anchorScroll
which will do that immediately when the view is being displayed (which is before you asynchronously load your data)
The best way to resolve that problem is to use the resolve property in the routes to load everything before the page is transitioned. Check my blog http://polycademy.com/blog/id/147/preloading_page_content_like_youtube_using_angularjs for more info on that.
A quicker solution is to use the delay or use the event listener to listen for an event that you broadcast when the content is loaded. This is a bit hacky and it will cause a flicker, but I used on a site to quickly resolve the issue.