Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove hashchange event from Angular, or prevent Angular from rewriting anchor links

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:

  1. 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).

  2. 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.

like image 658
qJake Avatar asked Jun 20 '16 16:06

qJake


3 Answers

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

like image 67
ScottL Avatar answered Nov 05 '22 00:11

ScottL


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.

like image 35
qJake Avatar answered Nov 05 '22 02:11

qJake


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 
  });
like image 45
Tyson Avatar answered Nov 05 '22 02:11

Tyson