Comment gérer la liaison de hachage d'ancrage à AngularJS

est-ce que l'un d'entre vous sait comment bien manier le hachage d'ancrage dans AngularJS ?

j'ai le balisage suivant pour une FAQ simple-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>

en cliquant sur l'un des liens ci-dessus AngularJS intercepte et m'achemine vers une page complètement différente (dans mon cas, une page 404 car il n'y a pas de routes correspondant aux liens.)

ma première pensée a été de créer une route correspondant à " / faq/: chapitre " et dans le controller correspondant cochez $routeParams.chapter après un élément correspondant et utilisez ensuite jQuery pour faire défiler vers le bas.

mais alors AngularJS chie encore sur moi et défile juste en haut de la page de toute façon.

donc, quelqu'un ici a fait quelque chose de similaire dans le passé et sait une bonne solution à elle?

Edit: Passer au html5Mode devrait résoudre mes problèmes, mais nous avons un peu à prendre en charge IE8+ de toute façon donc J'ai peur que cela n'est pas une solution retenue :/

311
demandé sur Sunil Garg 2013-02-05 20:29:38

27 réponses

vous recherchez $anchorScroll() .

Voici la documentation (merdique).

et voici la source.

en gros, vous l'injectez et l'appelez dans votre contrôleur, et il vous fera défiler vers n'importe quel élément avec l'id trouvé dans $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>

voici un plongeur pour démontrer

EDIT: pour l'utiliser avec de routage

configurez votre routage angulaire comme d'habitude, puis ajoutez juste le code suivant.

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();  
  });
});

et votre lien ressemblerait à ceci:

<a href="#/test?scrollTo=foo">Test/Foo</a>

voici un Plunker montrant le défilement avec routage et $ anchorScroll

et encore plus simple:

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();  
  });
});

et votre lien ressemblerait à ceci:

<a href="#/test#foo">Test/Foo</a>
369
répondu Ben Lesh 2018-03-21 22:15:33

dans mon cas, j'ai remarqué que la logique de routage fonctionnait si je modifiais le $location.hash() . Le truc suivant a fonctionné..

$scope.scrollTo = function(id) {
    var old = $location.hash();
    $location.hash(id);
    $anchorScroll();
    //reset to old to keep any additional routing logic from kicking in
    $location.hash(old);
};
165
répondu slugslog 2018-03-15 22:47:27

il n'est pas nécessaire de changer le routage ou quoi que ce soit d'autre juste besoin d'utiliser target="_self" lors de la création des liens

exemple:

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

et utilisez l'attribut id dans votre html éléments comme ceci:

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

il n'est pas nécessaire d'utiliser ## comme indiqué/mentionné dans les commentaires; -)

51
répondu Mauricio Gracia Gutierrez 2016-01-17 13:03:01
<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="faq-3">Question 3</h3>
41
répondu lincolnge 2014-04-02 07:34:41

si vous connaissez toujours la route, vous pouvez simplement ajouter l'ancre comme ceci:

href="#/route#anchorID

route est la route angulaire actuelle et anchorID correspond à un <a id="anchorID"> quelque part sur la page

19
répondu cab1113 2013-10-14 18:57:10

C'était ma solution en utilisant une directive qui semble plus angulaire-y parce que nous traitons avec le DOM:

Plnkr ici

github

CODE

angular.module('app', [])
.directive('scrollTo', function ($location, $anchorScroll) {
  return function(scope, element, attrs) {

    element.bind('click', function(event) {
        event.stopPropagation();
        var off = scope.$on('$locationChangeStart', function(ev) {
            off();
            ev.preventDefault();
        });
        var location = attrs.scrollTo;
        $location.hash(location);
        $anchorScroll();
    });

  };
});

HTML

<ul>
  <li><a href="" scroll-to="section1">Section 1</a></li>
  <li><a href="" scroll-to="section2">Section 2</a></li>
</ul>

<h1 id="section1">Hi, I'm section 1</h1>
<p>
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. 
 Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. 
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. 
Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.
</p>

<h1 id="section2">I'm totally section 2</h1>
<p>
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. 
 Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. 
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. 
Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.
</p>

j'ai utilisé le service $anchorScroll. Pour contrer le rafraîchissement de la page qui va de pair avec le changement de hachage je suis allé de l'avant et annulation de l'événement locationChangeStart. Cela a fonctionné pour moi parce que j'ai eu une page d'aide accrochée à un commutateur ng et les rafraîchissements briseraient esentiellement l'application.

14
répondu KhalilRavanna 2015-01-28 22:52:44

$anchorScroll fonctionne pour cela, mais il ya une bien meilleure façon de l'utiliser dans les versions plus récentes D'Angular.

maintenant, $anchorScroll accepte le hachage comme un argument optionnel, donc vous n'avez pas à changer $location.hash du tout. ( documentation )

C'est la meilleure solution car elle n'affecte pas la route du tout. Je n'ai pas pu faire fonctionner les autres solutions parce que j'utilise ngRoute et la route serait rechargez dès que j'ai mis $location.hash(id) , avant que $anchorScroll puisse faire sa magie.

Voici comment l'utiliser... premièrement, dans la directive ou le contrôleur:

$scope.scrollTo = function (id) {
  $anchorScroll(id);  
}

et puis dans la vue:

<a href="" ng-click="scrollTo(id)">Text</a>

aussi, si vous avez besoin de tenir compte d'une barre de navigation fixe (ou D'une autre interface utilisateur), vous pouvez définir l'offset pour $ancherscroll comme ceci (dans la fonction d'exécution du module principal):

.run(function ($anchorScroll) {
   //this will make anchorScroll scroll to the div minus 50px
   $anchorScroll.yOffset = 50;
});
13
répondu Rebecca 2016-05-21 11:35:10

essayer de définir un préfixe de hachage pour les routes angulaires $locationProvider.hashPrefix('!')

exemple complet:

angular.module('app', [])
  .config(['$routeProvider', '$locationProvider', 
    function($routeProvider, $locationProvider){
      $routeProvider.when( ... );
      $locationProvider.hashPrefix('!');
    }
  ])
5
répondu Maxim Grach 2013-02-15 08:28:37

j'ai contourné cela dans la logique de route pour mon application.

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;
      }
    });
}
5
répondu nicksanta 2014-09-11 13:06:08

C'est un vieux post, mais j'ai passé un long moment à la recherche de diverses solutions, donc je voulais partager un plus simple. J'ai juste ajouté target="_self" à la balise <a> pour le réparer. Le lien fonctionne et m'emmène à l'emplacement approprié sur la page.

cependant, Angular injecte encore une certaine bizarrerie avec le # dans l'URL de sorte que vous pouvez rencontrer des problèmes en utilisant le bouton back pour la navigation et tels après avoir utilisé cette méthode.

5
répondu Benjamin 2015-06-18 12:33:19

c'est peut-être un nouvel attribut pour ngView, mais j'ai réussi à obtenir des liens de hachage d'ancrage pour fonctionner avec angular-route en utilisant l'attribut ngView autoscroll et "double-hachage".

ngView (voir autoscroll)

(le code suivant a été utilisé avec la sangle angulaire)

<!-- use the autoscroll attribute to scroll to hash on $viewContentLoaded -->    
<div ng-view="" autoscroll></div>

<!-- A.href link for bs-scrollspy from angular-strap -->
<!-- A.ngHref for autoscroll on current route without a location change -->
<ul class="nav bs-sidenav">
  <li data-target="#main-html5"><a href="#main-html5" ng-href="##main-html5">HTML5</a></li>
  <li data-target="#main-angular"><a href="#main-angular" ng-href="##main-angular" >Angular</a></li>
  <li data-target="#main-karma"><a href="#main-karma" ng-href="##main-karma">Karma</a></li>
</ul>
4
répondu michael 2014-06-24 14:48:29

je pourrais le faire de cette manière:

<li>
<a href="#/#about">About</a>
</li>
3
répondu Niru 2016-05-21 09:09:05

Voici une sorte de contournement sale en créant une directive personnalisée qui va défiler à l'élément spécifié (avec le code dur "faq")

app.directive('h3', function($routeParams) {
  return {
    restrict: 'E',
    link: function(scope, element, attrs){        
        if ('faq'+$routeParams.v == attrs.id) {
          setTimeout(function() {
             window.scrollTo(0, element[0].offsetTop);
          },1);        
        }
    }
  };
});

http://plnkr.co/edit/Po37JFeP5IsNoz5ZycFs?p=preview

2
répondu Valentyn Shybanov 2013-02-05 17:04:56
<a href="/#/#faq-1">Question 1</a>
<a href="/#/#faq-2">Question 2</a>
<a href="/#/#faq-3">Question 3</a>
2
répondu felipe_dmz 2015-05-19 20:32:43

ma solution avec ng-route était cette simple directive:

   app.directive('scrollto',
       function ($anchorScroll,$location) {
            return {
                link: function (scope, element, attrs) {
                    element.click(function (e) {
                        e.preventDefault();
                        $location.hash(attrs["scrollto"]);
                        $anchorScroll();
                    });
                }
            };
    })

le html ressemble à:

<a href="" scrollTo="yourid">link</a>
2
répondu MrFlo 2018-03-15 20:32:26

vous pouvez essayer d'utiliser anchorScroll .

exemple

donc le contrôleur serait:

app.controller('MainCtrl', function($scope, $location, $anchorScroll, $routeParams) {
  $scope.scrollTo = function(id) {
     $location.hash(id);
     $anchorScroll();
  }
});

et la vue:

<a href="" ng-click="scrollTo('foo')">Scroll to #foo</a>

...et pas de secret pour l'anchor id:

<div id="foo">
  This is #foo
</div>
1
répondu Edmar Miyake 2013-10-24 02:26:47

j'essayais de faire défiler mon application angulaire vers un chargement d'une ancre opon et j'ai couru dans les règles de réécriture D'URL de $routeProvider.

après de longues expérimentations, je me suis posé la question suivante:

  1. enregistrer un document.gestionnaire d'événement onload de la .run() de la section de le module de l'application angulaire.
  2. dans le handler découvrez ce que l'original a balise d'ancrage était censé être en faisant de la chaîne des opérations.
  3. position de surpassement.le hachage avec l'étiquette d'ancrage décollée (qui fait que $routeProvider l'écrase immédiatement à nouveau avec "#/" règle. Mais c'est très bien, car Angulaire est maintenant synchronisé avec ce qui se passe dans L'URL 4) appelez $anchorScroll().

angular.module("bla",[]).}])
.run(function($location, $anchorScroll){
         $(document).ready(function() {
	 if(location.hash && location.hash.length>=1)    		{
			var path = location.hash;
			var potentialAnchor = path.substring(path.lastIndexOf("/")+1);
			if ($("#" + potentialAnchor).length > 0) {   // make sure this hashtag exists in the doc.                          
			    location.hash = potentialAnchor;
			    $anchorScroll();
			}
		}	 
 });
1
répondu Stoyan Kenderov 2014-10-22 02:59:39

je ne suis pas sûr à 100% si cela fonctionne tout le temps, mais dans mon application, cela me donne le comportement attendu.

disons que vous êtes sur à propos de page et vous avez la route suivante:

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

maintenant, en vous 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>

en conclusion

y compris le nom de la page avant l'ancre a fait le tour pour moi. Laissez-moi savoir à propos de votre pensées.

à la Baisse

cela va re-rendre la page et puis faire défiler jusqu'à l'ancre.

mise à JOUR

une meilleure façon est d'ajouter ce qui suit:

<a href="#tab1" onclick="return false;">First Part</a>
1
répondu Brian 2014-11-21 18:29:24

Si vous n'aimez pas utiliser ng-click voici une solution alternative. Il utilise un filter pour générer l'url correcte basée sur l'état actuel. Mon exemple utilise ui.routeur .

l'avantage est que l'utilisateur verra où le lien passe en stationnaire.

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

le filtre:

.filter('anchor', ['$state', function($state) {
    return function(id) {
        return '/#' + $state.current.url + '#' + id;
    };
}])
1
répondu Reimund 2016-04-06 13:11:03

obtenez votre fonction de défilement facilement. Il prend également en charge animation / défilement lisse comme une caractéristique supplémentaire. Détails pour Angulaire de Défilement de la bibliothèque:

Github - https://github.com/oblador/angular-scroll

la Charmille : bower install --save angular-scroll

mnp : npm install --save angular-scroll

version abrégée - seulement 9kb

défilement en douceur (défilement animé) - Oui

Spy Scroll - yes

Documentation - excellent

Demo - http://oblador.github.io/angular-scroll /

Espérons que cette aide.

1
répondu Akash 2016-04-12 09:02:43

basé sur @Stoyan j'ai trouvé la solution suivante:

app.run(function($location, $anchorScroll){
    var uri = window.location.href;

    if(uri.length >= 4){

        var parts = uri.split('#!#');
        if(parts.length > 1){
            var anchor = parts[parts.length -1];
            $location.hash(anchor);
            $anchorScroll();
        }
    }
});
1
répondu ThatMSG 2018-04-26 21:02:39

sur le changement de Route, il fera défiler vers le haut de la page.

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

mettez ce code sur votre contrôleur.

0
répondu Praveen M P 2015-01-12 13:47:29

dans mon esprit @slugslog l'avait, mais je changerais une chose. J'utiliserais le remplacement à la place pour que tu n'aies pas à le remettre en arrière.

$scope.scrollTo = function(id) {
    var old = $location.hash();
    $location.hash(id).replace();
    $anchorScroll();
};

Docs recherche de" remplacer méthode "

0
répondu Jackie 2015-02-04 19:51:00

aucune de la solution ci-dessus ne fonctionne pour moi, mais je viens d'essayer, et ça a fonctionné,

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

donc j'ai réalisé que je devais notifier la page pour commencer avec la page d'index et ensuite utiliser l'ancre traditionnelle.

0
répondu windmaomao 2015-04-21 17:57:33

parfois dans angularjs application hachage de la navigation ne fonctionne pas et bootstrap jQuery les bibliothèques javascript font largement usage de ce type de navigation, pour le faire fonctionner ajouter target="_self" à l'étiquette d'ancrage. par exemple <a data-toggle="tab" href="#id_of_div_to_navigate" target="_self">

0
répondu Kulbhushan Chaskar 2016-03-30 16:09:55

voir https://code.angularjs.org/1.4.10/docs/api/ngRoute/provider / $routeProvider

[reloadOnSearch=true] - {boolean=} - rechargement de la route lorsque seulement $emplacement.recherche() ou $lieu.hash() change.

mettre ceci à false a fait le tour sans tout ce qui précède pour moi.

0
répondu geekdenz 2016-05-21 11:33:30

J'utilise AngularJS 1.3.15 et on dirait que je n'ai rien à faire de spécial.

https://code.angularjs.org/1.3.15/docs/api/ng/provider / $ancherscrollprovider

donc, les travaux suivants pour moi dans mon html:

<ul>
  <li ng-repeat="page in pages"><a ng-href="#{{'id-'+id}}">{{id}}</a>
  </li>
</ul>
<div ng-attr-id="{{'id-'+id}}" </div>

Je n'ai pas eu à faire de changements à mon contrôleur ou JavaScript du tout.

0
répondu Digant C Kasundra 2016-05-21 11:36:58