Reputation: 17139
We have a project which uses Angular, but only for the UI binding/AJAX aspect of it, not for any sort of routing or SPA functionality.
We want to be able to use anchor links (#section-2
) in articles we write within the CMS we have chosen, as well as use anchor links from other pages (/my-page#section-C
), but Angular rewrites these to #/section-2
, which breaks the anchor links that the CMS sets up.
It is not possible to augment the CMS to modify how anchor links are handled.
Is it possible to either:
Remove the hashchange
event binding from within Angular? I see that this event is attached to in the source file src/ng/browser.js
where it handles some of the routing and link rewriting, but it's inside of a closure so it cannot be accessed directly (and we are linking to Angular from a CDN so it is not possible to modify the Angular source, plus we don't want to have to maintain our own "custom" Angular source).
Set an option or call a configuration method which ultimately disables the entire routing aspect of Angular and prevents it from rewriting any sort of links? (Or, is there a way to not include this portion of Angular, but still retain the controller/UI binding/AJAX functionality?)
Note that I have already tried this:
$locationProvider.html5Mode(true)
However it renders all other links on the site inoperable because all links are passed through Angular for processing. So if I link to the homepage (<a href="/">Home</a>
) and click the link with html5mode
on, the link does nothing.
Upvotes: 11
Views: 1940
Reputation: 14734
Angular's $locationProvider.html5Mode function with it's rewriteLinks
setting is what you're looking for. It will put angular into a mode where $location can still be used to read and write the browser's url, but it won't ever attempt to hijack link clicks and trigger angular's SPA routing.
eg:
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
});
Upvotes: 2
Reputation: 64
I had a similar problem when using angular with wordpress and found a really simple fix. All you have to do is remove all $location injection in your controllers. When you inject $location service (whether you use it or not) it hijacks the # behaviour.
This means that you have to scour through all your controllers, directives etc and make sure that the $location service is not injected anywhere.
HTH
Upvotes: 0
Reputation: 822
After setting $locationProvider.html5Mode(true), did you also set a <base>
in the <head>
of your document?
<html>
<head>
<base href="/">
</head>
</html>
Have a look here:
"There are 2 things that need to be done.
or here
Upvotes: 0
Reputation: 10916
But why not use ng-route? it would totally solve your issues. using Ng routes you can achieve the following (which is what you want).
<a href="http://www.example.com/base/#section-A"> Section A</a>
<a href="http://www.example.com/base/my-page#section-C">Another page</a>
<a href="/other-base/another?search">external</a>
here is the app.js snippet
app.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
When you use HTML5 history API mode, you will not need special hashbang links. All you have to do is specify regular URL links, such as: <a href="/some?foo=bar">link</a>
When a user clicks on this link,
In a legacy browser, the URL changes to /index.html#!/some?foo=bar
In a modern browser, the URL changes to /some?foo=bar
In cases like the following, links are not rewritten; instead, the browser will perform a full page reload to the original link.
Links that contain target element
Example: <a href="/ext/link?a=b" target="_self">link</a>
Absolute links that go to a different domain
Example: <a href="http://angularjs.org/">link</a>
Links starting with '/' that lead to a different base path
Example: <a href="/not-my-base/link">link</a>
Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url base in the head of your main html file (<base href="/my-base/index.html">
) unless html5Mode.requireBase is set to false in the html5Mode definition object passed to $locationProvider.html5Mode(). With that, relative urls will always be resolved to this base url, even if the initial url of the document was different.
There is one exception: Links that only contain a hash fragment (e.g. <a href="#target">
) will only change $location.hash() and not modify the url otherwise. This is useful for scrolling to anchors on the same page without needing to know on which page the user currently is.
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html). Requiring a tag is also important for this case, as it allows Angular to differentiate between the part of the url that is the application base and the path that should be handled by the application.
Upvotes: -2
Reputation: 17139
As somewhat of a workaround (and certainly not best practice), I ended up modifying the Angular source in order to remove the URL rewriting.
I made a few changes, but I believe the one that caused anchor links to work again was adding a return;
statement on Line 844 of location.js
in the Angular source:
https://github.com/angular/angular.js/blob/master/src/ng/location.js#L844
This short-circuits around much of the URL rewriting functionality.
I also completely removed Lines 262-264 of browser.js
, which removes Angular's hook on the hashchange
event:
https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L262-264
This didn't seem to affect any of the binding features of Angular, but it did cause anchor links to start working again.
Upvotes: 2
Reputation: 1755
I believe that you want $anchorScroll. See this related answer: How to handle anchor hash linking in AngularJS
Here is an example of how it would work. The hash is just treated as part of the id:
app.controller('TestCtrl', function($location, $anchorScroll) {
var vm = this;
vm.scrollTo = function(id) {
$location.hash(id);
$anchorScroll();
}
});
<a ng-click="vm.scrollTo('#foo')">Foo</a>
<div id="#foo">Here you are</div>
See plunker demonstrating $anchorScroll
With routing, you can change the link to:
<a href="#/test##foo">Test/Foo</a>
and add this to the run configuration:
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
if($location.hash()) {
$anchorScroll();
}
});
See plunker demonstrating scrolling with routing and $anchorScroll
Upvotes: 3