How to handle anchor hash linking in AngularJS

2018-12-31 12:15发布

Do any of you know how to nicely handle anchor hash linking in AngularJS?

I have the following markup for a simple FAQ-page

<a href="#faq-1">Question 1</a>
<a href="#faq-2">Question 2</a>
<a href="#faq-3">Question 3</a>

<h3 id="faq-1">Question 1</h3>
<h3 id="faq-2">Question 2</h3>
<h3 id="fa1-3">Question 3</h3>

When clicking on any of the above links AngularJS intercepts and routes me to a completely different page (in my case, a 404-page as there are no routes matching the links.)

My first thought was to create a route matching "/faq/:chapter" and in the corresponding controller check $routeParams.chapter after a matching element and then use jQuery to scroll down to it.

But then AngularJS shits on me again and just scrolls to the top of the page anyway.

So, anyone here done anything similar in the past and knows a good solution to it?

Edit: Switching to html5Mode should solve my problems but we kinda have to support IE8+ anyway so I fear it's not an accepted solution :/

27条回答
人间绝色
2楼-- · 2018-12-31 13:00

If you don't like to use ng-click here's an alternate solution. It uses a filter to generate the correct url based on the current state. My example uses ui.router.

The benefit is that the user will see where the link goes on hover.

<a href="{{ 'my-element-id' | anchor }}">My element</a>

The filter:

.filter('anchor', ['$state', function($state) {
    return function(id) {
        return '/#' + $state.current.url + '#' + id;
    };
}])
查看更多
无与为乐者.
3楼-- · 2018-12-31 13:02

Try to set a hash prefix for angular routes $locationProvider.hashPrefix('!')

Full example:

angular.module('app', [])
  .config(['$routeProvider', '$locationProvider', 
    function($routeProvider, $locationProvider){
      $routeProvider.when( ... );
      $locationProvider.hashPrefix('!');
    }
  ])
查看更多
与君花间醉酒
4楼-- · 2018-12-31 13:03

I am not 100% sure if this works all the time, but in my application this gives me the expected behavior.

Lets say you are on ABOUT page and you have the following route:

yourApp.config(['$routeProvider', 
    function($routeProvider) {
        $routeProvider.
            when('/about', {
                templateUrl: 'about.html',
                controller: 'AboutCtrl'
            }).
            otherwise({
                redirectTo: '/'
            });
        }
]);

Now, in you HTML

<ul>
    <li><a href="#/about#tab1">First Part</a></li>
    <li><a href="#/about#tab2">Second Part</a></li>
    <li><a href="#/about#tab3">Third Part</a></li>                      
</ul>

<div id="tab1">1</div>
<div id="tab2">2</div>
<div id="tab3">3</div>

In conclusion

Including the page name before the anchor did the trick for me. Let me know about your thoughts.

Downside

This will re-render the page and then scroll to the anchor.

UPDATE

A better way is to add the following:

<a href="#tab1" onclick="return false;">First Part</a>
查看更多
一个人的天荒地老
5楼-- · 2018-12-31 13:04

On Route change it will scroll to the top of the page.

 $scope.$on('$routeChangeSuccess', function () {
      window.scrollTo(0, 0);
  });

put this code on your controller.

查看更多
几人难应
6楼-- · 2018-12-31 13:06

I got around this in the route logic for my app.

function config($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: '/partials/search.html',
      controller: 'ctrlMain'
    })
    .otherwise({
      // Angular interferes with anchor links, so this function preserves the
      // requested hash while still invoking the default route.
      redirectTo: function() {
        // Strips the leading '#/' from the current hash value.
        var hash = '#' + window.location.hash.replace(/^#\//g, '');
        window.location.hash = hash;
        return '/' + hash;
      }
    });
}
查看更多
君临天下
7楼-- · 2018-12-31 13:06
<a href="/#/#faq-1">Question 1</a>
<a href="/#/#faq-2">Question 2</a>
<a href="/#/#faq-3">Question 3</a>
查看更多
登录 后发表回答