How to handle anchor hash linking in AngularJS
You're looking for $anchorScroll()
.
Here's the (crappy) documentation.
And here's the source.
Basically you just inject it and call it in your controller, and it will scroll you to any element with the id found in $location.hash()
app.controller('TestCtrl', function($scope, $location, $anchorScroll) {
$scope.scrollTo = function(id) {
$location.hash(id);
$anchorScroll();
}
});
<a ng-click="scrollTo('foo')">Foo</a>
<div id="foo">Here you are</div>
Here is a plunker to demonstrate
EDIT: to use this with routing
Set up your angular routing as usual, then just add the following code.
app.run(function($rootScope, $location, $anchorScroll, $routeParams) {
//when the route is changed scroll to the proper element.
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});
});
and your link would look like this:
<a href="#/test?scrollTo=foo">Test/Foo</a>
Here is a Plunker demonstrating scrolling with routing and $anchorScroll
And even simpler:
app.run(function($rootScope, $location, $anchorScroll) {
//when the route is changed scroll to the proper element.
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
if($location.hash()) $anchorScroll();
});
});
and your link would look like this:
<a href="#/test#foo">Test/Foo</a>
AngularJs with hash in href breaks scrolling and transforms url to hash+fwslash+id
html5Mode
As described in angular add slash before hash in url I tried to turn on the html5 mode by adding:
app.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})
I have set up the base tag in the head section.
These settings made it to start working as expected.
... but I would mention that once the location in the address bar got updated to the referenced hash if I clicked the link again, it just went down a bit and not to the referenced location. Clicking on links with different anchors it works well. Not sure if this is a general bug or only some of my settings are backfiring.
Anchor links in Angularjs?
There are a few ways to do this it seems.
Option 1: Native Angular
Angular provides an $anchorScroll
service, but the documentation is severely lacking and I've not been able to get it to work.
Check out http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html for some insight into $anchorScroll
.
Option 2: Custom Directive / Native JavaScript
Another way I tested out was creating a custom directive and using el.scrollIntoView()
.
This works pretty decently by basically doing the following in your directive link function:
var el = document.getElementById(attrs.href);
el.scrollIntoView();
However, it seems a bit overblown to do both of these when the browser natively supports this, right?
Option 3: Angular Override / Native Browser
If you take a look at http://docs.angularjs.org/guide/dev_guide.services.$location and its HTML Link Rewriting section, you'll see that links are not rewritten in the following:
Links that contain target element
Example:
<a href="/ext/link?a=b" target="_self">link</a>
So, all you have to do is add the target
attribute to your links, like so:
<a href="#anchorLinkID" target="_self">Go to inpage section</a>
Angular defaults to the browser and since its an anchor link and not a different base url, the browser scrolls to the correct location, as desired.
I went with option 3 because its best to rely on native browser functionality here, and saves us time and effort.
Gotta note that after a successful scroll and hash change, Angular does follow up and rewrite the hash to its custom style. However, the browser has already completed its business and you are good to go.
How does AngularJS routing affect simple scroll to top page links?
Yes if you're using conventional anchor tag with href hash linking, then it'll conflict with routing. In angular there's service called $anchorScroll
to do that, so your html should be:
<a ng-click="goTo('top')" class="footer__top">Back to top</a>
And in controller of that view have function goTo as:
$scope.goTo = function(id) {
$location.hash(id);
$anchorScroll();
};
Make sure you've injected $location
& $anchorScroll
as dependencies inside controller.
Plunker
Now above solution is for having hash linking on same page/route. But i you need such in other route then you can handle that centrally on event of $routeChangeSuccess
or $stateChangeSuccess
or in recent ui-router version Transition.onSuccess
as:
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});
And in some other view have anchor tags like:
<a href="#route1?scrollTo=foo">route1 / Foo</a>
<a href="#route2?scrollTo=bar">route2 / Bar</a>
Plunker
Empty anchor tag value using hash or javascript in Angular
According to the AngularJS docs for the A directive, you should be using href=""
.
The reasoning for this is to allow easy creation of action links with ngClick directive without changing the location or causing page reloads, e.g.:
<a href="" ng-click="model.$save()">Save</a>
How to use native anchor links with angularjs
This topic was further discussed here:
How to handle anchor hash linking in AngularJS
I used a variation from that thread
if $location.$$url[0]== '#'
$location.hash($location.$$url.replace('#', ''))
$anchorScroll()
that basically lets me prefix any anchor links with an additional #
and angularjs treats them as traditional anchor
Related Topics
Webdriver Click() VS JavaScript Click()
Determining Image File Size + Dimensions via JavaScript
How to Get the Size of a JavaScript Object
How to Check If Dst (Daylight Saving Time) Is in Effect, and If So, the Offset
JavaScript - Href VS Onclick for Callback Function on Hyperlink
Warn User Before Leaving Web Page with Unsaved Changes
Differencebetween 'New Object()' and Object Literal Notation
Execute the Setinterval Function Without Delay the First Time
Jquery .Ready in a Dynamically Inserted Iframe
Call an Asynchronous JavaScript Function Synchronously
How to Prevent Enter Keypress to Submit a Web Form
How to Add New Array Elements at the Beginning of an Array in JavaScript
How to Get a JavaScript Object's Class
How to Check If a String Contains Text from an Array of Substrings in JavaScript