web-dev-qa-db-fra.com

Comment prévenir Défaut sur les tags d'ancrage?

Disons que j'ai une balise d'ancrage telle que

<a href="#" ng-click="do()">Click</a>

Comment puis-je empêcher le navigateur d’accéder à # in AngularJS?

340
Micael

UPDATE: J'ai depuis changé d'avis sur cette solution. Après plus de développement et de temps passé à travailler dessus, je pense qu'une meilleure solution à ce problème est la suivante:

<a ng-click="myFunction()">Click Here</a>

Et puis mettez à jour votre css pour avoir une règle supplémentaire:

a[ng-click]{
    cursor: pointer;
}

C'est beaucoup plus simple et fournit exactement la même fonctionnalité et est beaucoup plus efficace. J'espère que cela pourrait être utile à quiconque recherchant cette solution à l'avenir.


Ce qui suit est ma solution précédente, que je laisse ici pour des raisons héritées:

Si vous rencontrez beaucoup ce problème, une directive simple permettant de résoudre ce problème est la suivante:

app.directive('a', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            if(attrs.ngClick || attrs.href === '' || attrs.href === '#'){
                elem.on('click', function(e){
                    e.preventDefault();
                });
            }
        }
   };
});

Il vérifie toutes les balises d'ancrage (<a></a>) pour voir si leur attribut href est une chaîne vide ("") ou un hachage ('#') ou s'il y a un ng-click assignation. S'il trouve l'une de ces conditions, il intercepte l'événement et empêche le comportement par défaut.

Le seul inconvénient est qu'il exécute cette directive pour toutes les balises d'ancrage. Donc, si vous avez beaucoup de balises d'ancrage sur la page et que vous souhaitez uniquement empêcher le comportement par défaut pour un petit nombre d'entre elles, cette directive n'est pas très efficace. Cependant, comme je veux presque toujours preventDefault, j'utilise cette directive dans toutes mes applications AngularJS.

256
tennisgent

Selon le docs pour ngHref , vous devriez pouvoir laisser le href ou faire href = "".

<input ng-model="value" /><br />
<a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
<a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
<a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
<a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
319
Chris

Vous pouvez passer l'objet $ event à votre méthode et appeler $event.preventDefault(), afin que le traitement par défaut ne se produise pas:

<a href="#" ng-click="do($event)">Click</a>

// then in your controller.do($event) method
$event.preventDefault()
234
mna

Je préfère utiliser directives pour ce genre de chose. Voici un exemple

<a href="#" ng-click="do()" eat-click>Click Me</a>

Et le code de directive pour eat-click:

module.directive('eatClick', function() {
    return function(scope, element, attrs) {
        $(element).click(function(event) {
            event.preventDefault();
        });
    }
})

Vous pouvez maintenant ajouter l'attribut eat-click à n'importe quel élément et il obtiendra preventDefault() 'automatiquement.

Avantages:

  1. Vous n'avez pas besoin de passer l'objet $event laid dans votre fonction do().
  2. Votre contrôleur est davantage testable par unité car il n'a pas besoin de tronquer l'objet $event
110
djsmith

Bien que Renaud a donné une excellente solution

<a href="#" ng-click="do(); $event.preventDefault()">Click</a> 

J'ai personnellement constaté que vous aviez également besoin de $ event.stopPropagation () dans certains cas pour éviter certains des effets secondaires.

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">
    Click</a>

sera ma solution

52
zainengineer
ng-click="$event.preventDefault()"
33
The Whiz of Oz

La solution la plus simple que j'ai trouvée est celle-ci:

<a href="#" ng-click="do(); $event.preventDefault()">Click</a>
33
Clément Renaud

Donc, en lisant ces réponses, @Chris a toujours la réponse la plus "correcte", je suppose, mais il y a un problème, il ne montre pas le "pointeur" ....

Il existe donc deux manières de résoudre ce problème sans avoir à ajouter de curseur: style de pointeur:

  1. Utilisez javascript:void(0) au lieu de #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
    
  2. Utilisez $event.preventDefault() dans la directive ng-click (pour ne pas compromettre votre contrôleur avec des références liées à DOM):

    <a href="#dontGoHere" ng-click="doSomething(); $event.preventDefault()">Do Something</a>
    

Personnellement, je préfère le premier au second. javascript:void(0) a d'autres avantages qui sont discuté ici . Il est également question de "JavaScript non intrusif" dans ce lien effroyablement récent, qui ne s'applique pas nécessairement directement à une application angular.

10
Ben Lesh

Vous pouvez faire comme suit

1.Remove href attribut de la balise d'ancrage (a)

2. Placez le curseur du pointeur dans les éléments css à ng

 [ng-click],
 [data-ng-click],
 [x-ng-click] {
     cursor: pointer;
 }
9
Fizer Khan

HTML

ici pure angularjs: près de la fonction ng-click, vous pouvez écrire la fonction preventDefault () en séparant les points-virgules

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">Click me</a>

JS

$scope.do = function() {
    alert("do here anything..");
}

(ou)

vous pouvez procéder de cette façon, cela a déjà été discuté ici.

HTML

<a href="#" ng-click="do()">Click me</a>

JS

$scope.do = function(event) {
    event.preventDefault();
    event.stopPropagation()
}

Essayez cette option que je peux voir n'est pas encore listée ci-dessus:

<a href="" ng-click="do()">Click</a>
6
pollux1er

Le moyen le plus sûr d’éviter les événements sur un href serait de le définir comme

<a href="javascript:void(0)" ....>
5
Michael Drob

si toujours pertinent:

<a ng-click="unselect($event)" />

...

scope.unselect = function( event ) {
 event.preventDefault();
 event.stopPropagation();
}

...
5
xac

Puisque vous créez une application Web, pourquoi avez-vous besoin de liens?

Échangez vos ancres contre des boutons!

<button ng-click="do()"></button>
5
sidonaldson

C'est ce que je fais toujours. Fonctionne comme un charme!

<a href ng-click="do()">Click</a>
4
Catfish

J'irais avec:

<a ng-click="do()">Click</a>
  • parce que selon la documentation, vous devriez pouvoir quitter le href et ensuite, Angular gérera le paramètre de prévention par défaut pour vous!

Tout ce qui a été empêché par défaut a été source de confusion pour moi, donc j’ai créé un JSFiddle , où illustrer quand et où Angular empêche le défaut .

Le JSFiddle utilise une directive de Angular - elle devrait donc être EXACTEMENT la même. Vous pouvez voir le code source ici: n code source de balise

J'espère que cela aidera à clarifier certains.

J'aurais aimé poster le document sur ngHref mais je ne peux pas à cause de ma réputation.

4
martinmose

Ou si vous avez besoin d’Inline, vous pouvez le faire:

<a href="#" ng-click="show = !show; $event.preventDefault()">Click to show</a>
3
ntekka

Beaucoup de réponses semblent être exagérées. POUR MOI, ça marche

 <a ng-href="#" ng-click="$event.preventDefault();vm.questionContainer($index)">{{question.Verbiage}}</a>
3
Tom Stickel

J'ai besoin de la présence de la valeur de l'attribut href pour la dégradation (lorsque js est désactivé), je ne peux donc pas utiliser l'attribut href vide (ou "#"), mais le code ci-dessus n'a pas fonctionné pour moi, car j'ai besoin d'un événement ( e) variable. J'ai créé ma propre directive:

angular.module('MyApp').directive('clickPrevent', function() {
  return function(scope, element, attrs) {
    return element.on('click', function(e) {
      return e.preventDefault();
    });
  };
});

En HTML:

<a data-click-prevent="true" href="/users/sign_up" ng-click="openSignUpModal()">Sign up</a>
1
focused

si vous ne voulez jamais aller à href ... vous devriez changer votre balisage et utiliser un bouton, pas une balise d'ancrage, car sémantiquement, ce n'est ni une ancre ni un lien. Inversement, si vous avez un bouton qui vérifie puis redirige, il doit s'agir d'un tag lien/ancre et non d'un bouton ... à des fins de référencement et de test [insérer la suite de tests ici].

pour les liens que vous voulez seulement rediriger conditionnellement, comme inviter à enregistrer les modifications ou accuser réception d'un état modifié ... vous devez utiliser ng-click = "someFunction ($ event)" et dans someFunction sur votre validationError preventDefault et/ou StopPropagation.

aussi juste parce que vous pouvez ne signifie pas que vous devriez. javascript: void (0) a bien fonctionné dans la journée ... mais à cause des hackers néfastes, les navigateurs signalent les applications/sites qui utilisent javascript dans un href ... ne voit aucune raison de ducktype ci-dessus ..

nous sommes en 2016 car 2010 ne devrait être une raison nulle part pour utiliser des liens qui agissent comme des boutons ... Si vous devez toujours prendre en charge IE8 et les versions antérieures, vous devez réévaluer votre lieu d'activité.

1
PDA

Emprunter à la réponse de tennisgent. J'aime que vous n'ayez pas à créer de directive personnalisée pour ajouter tous les liens. Cependant, je ne pouvais pas le faire travailler dans IE8. Voici ce qui a finalement fonctionné pour moi (en utilisant angular 1.0.6).

Notez que 'bind' vous permet d'utiliser jqLite fourni par angular donc il n'est pas nécessaire d'envelopper avec jQuery complet. Requiert également la méthode stopPropogation.

.directive('a', [
    function() {
        return {
            restrict: 'E',
            link: function(scope, elem, attrs) {

                elem.bind('click', function(e){
                    if (attrs.ngClick || attrs.href === '' || attrs.href == '#'){
                        e.preventDefault();
                        e.stopPropagation();
                    }
                })
            }
        };
    }
])
1
Lukus

J'ai rencontré le même problème lors de l'utilisation d'ancres pour un menu déroulant angular bootstrap. La seule solution que j'ai trouvée qui évitait les effets secondaires indésirables (c'est-à-dire que la liste déroulante ne se fermait pas à cause de l'utilisation de preventDefault ()) consistait à utiliser les éléments suivants:

 <a href="javascript:;" ng-click="do()">Click</a>
1
cjackson

Vous pouvez désactiver la redirection d'URL dans Html5Mode de $ location pour atteindre l'objectif. Vous pouvez le définir dans le contrôleur spécifique utilisé pour la page. Quelque chose comme ça:

app.config(['$locationProvider', function ($locationProvider) {
    $locationProvider.html5Mode({
        enabled: true,
        rewriteLinks: false,
        requireBase: false
    });
}]);
0
Dash
/* NG CLICK PREVENT DEFAULT */

app.directive('ngClick', function () {
    return {
        link: function (scope, element, attributes) {
            element.click(function (event) {
                event.preventDefault();
                event.stopPropagation();
            });
        }
    };
});
0
user3638471

Ce que vous devez faire est d’omettre complètement l’attribut href.

Si vous regardez la code source pour la directive a element (qui fait partie du noyau Angular, _), vous remarquerez ce qui suit aux lignes 29 à 31:

if (!element.attr(href)) {
    event.preventDefault();
}

Ce qui signifie que Angular résout déjà le problème des liens sans href. Le seul problème que vous avez toujours est le problème css. Vous pouvez toujours appliquer le style de pointeur aux ancres avec des clics ng, par exemple:

a[ng-click] {
    /* Styles for anchors without href but WITH ng-click */
    cursor: pointer;
}

Ainsi, vous pouvez même rendre votre site plus accessible en marquant les liens réels avec un style subtil et différent, puis des liens remplissant des fonctions.

Bon codage!

0
Justus Romijn