Wie kann Default bei Ankertags verhindert werden?

342

Angenommen, ich habe ein Ankertag wie

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

Wie kann ich verhindern, dass der Browser in AngularJS zu # navigiert ?

Glimmer
quelle
14
Wie Chris unten sagt, lass das einfach weg href.
Jesse
13
Das sagt Chris nicht, Jesse, href=''um das Verhalten des Mauszeigers beizubehalten.
Oma
1
Sie entfernen einfach das # -Zeichen von href, es ist in Ordnung.
HENG Vongkol
4
Oder verwenden Sie einfach href = "javascript: void (0);" um den Zeiger zu behalten, aber keine Aktion zu haben (bis Sie einen weiteren Klick-Handler hinzufügen)
Robba
1
Könnten Sie bitte die akzeptierte Antwort in die beste und am meisten gewählte von Chris ändern - stackoverflow.com/a/11672909 ?
Piotr Dobrogost

Antworten:

259

UPDATE : Seitdem habe ich meine Meinung zu dieser Lösung geändert. Nach mehr Entwicklung und Zeitaufwand glaube ich, dass eine bessere Lösung für dieses Problem darin besteht, Folgendes zu tun:

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

Und aktualisieren Sie dann Ihre css, um eine zusätzliche Regel zu haben:

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

Es ist viel einfacher und bietet genau die gleiche Funktionalität und ist viel effizienter. Ich hoffe, dass dies für alle anderen hilfreich sein kann, die in Zukunft nach dieser Lösung suchen.


Das Folgende ist meine vorherige Lösung, die ich hier nur aus Legacy-Gründen lasse:

Wenn Sie dieses Problem häufig haben, ist eine einfache Anweisung, die dieses Problem beheben würde, die folgende:

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

Es überprüft alle Ankertags ( <a></a>), um festzustellen, ob ihr hrefAttribut entweder eine leere Zeichenfolge ( "") oder ein Hash ( '#') ist oder ob eine ng-clickZuweisung vorliegt. Wenn eine dieser Bedingungen gefunden wird, wird das Ereignis abgefangen und das Standardverhalten verhindert.

Der einzige Nachteil ist, dass diese Anweisung für alle Ankertags ausgeführt wird. Wenn Sie also viele Ankertags auf der Seite haben und das Standardverhalten nur für eine kleine Anzahl von Tags verhindern möchten, ist diese Anweisung nicht sehr effizient. Ich möchte dies jedoch fast immer preventDefault, daher verwende ich diese Anweisung überall in meinen AngularJS-Apps.

Tennisagent
quelle
2
Danke @matejkramny, sehr konstruktive Kritik. Irgendwelche Vorschläge, um es weniger "chaotisch" zu machen?
Tennisgent
1
Wie in anderen Antworten angegeben, hat ein leeres hrefAttribut in verschiedenen Browsern ein unterschiedliches Verhalten. Obwohl ich der Meinung bin, dass es bei weitem die sauberste und effizienteste Lösung ist, gibt es einige browserübergreifende Probleme. Die Verwendung des Direktivenansatzes ermöglicht es dem Browser, das <a>Tag wie gewohnt zu behandeln , dem OP jedoch die Antwort zu geben, nach der er gesucht hat.
Tennisgent
2
Dies funktioniert und alles andere als ernsthaft übertrieben für ein sehr einfaches Problem. Mit Angular können Sie mit $ event auf das Ereignisobjekt zugreifen, sodass Sie genau das tun können, was Sie in einfachen js- oder jquery-Klickereignissen tun würden. Siehe diese Antwort stackoverflow.com/a/19240232/1826354 und meinen Kommentar dazu
Charlie Martin
1
Ja. Du kannst. Es gibt zwei weitere Antworten in diesem Beitrag, die bereits das tun, was Sie beschreiben. Und ich stimme zu, es ist übertrieben. Deshalb habe ich das Update gemacht, das ich gemacht habe.
Tennisgent
6
Dies ist in Ordnung, wenn Sie sich nicht für die Barrierefreiheit Ihrer Website interessieren . Wenn Sie die href weglassen, können Sie mit der Tastatur nicht auf dieses Element zugreifen. Es sei denn, Sie haben einen Tabindex hinzugefügt. Warum nicht einfach PreventDefault verwenden? Dafür ist es da.
Duhseekoh
319

Gemäß den Dokumenten für ngHref sollten Sie in der Lage sein, die href wegzulassen oder href = "" zu tun.

<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 />
Chris
quelle
6
Es ist die einzig wirklich gute Antwort. Alles, was das Berühren des DOM oder nativer Ereignisse erfordert, ist fraglich
Vincent
4
Dies ist die richtige Antwort. Wenn Sie href aus dem <a> -Attribut entfernen, ruft AngularJS den Standard "Verhindern" auf:
pkozlowski.opensource
25
Der einzige Nachteil beim Weglassen des href-Attributs besteht darin, dass Sie den normalen Zeigercursor verlieren, wenn Sie mit der Maus über einen Link fahren. Sie können dies beheben, indem Sie Ihrem Stylesheet eine Regel hinzufügen: a: hover {cursor: pointer; }
Karlgold
35
Beachten Sie, dass das Tag dadurch auch nicht mehr tabellierbar ist, was nicht sehr barrierefrei ist.
Richard Szalay
3
Für mich sprudelt der Browser immer noch die Klickaktion: /
Matej
238

Sie können das $ event-Objekt an Ihre Methode übergeben und es aufrufen $event.preventDefault(), damit die Standardverarbeitung nicht erfolgt:

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

// then in your controller.do($event) method
$event.preventDefault()
mna
quelle
13
Ja, und Sie können auch $ event.stopPropagation () aufrufen, damit das Ereignis nicht in die Luft sprudelt (im Grunde haben Sie Zugriff auf das Ereignisobjekt, wie vom W3C definiert: w3.org/TR/DOM-Level-2- Events / events.html # Events-Event )
mna
1
Bitte beachten Sie, dass zu dem Zeitpunkt, als dies geschrieben wurde, das Leeren des href (oder das Fehlen) des IE8 / 9 und Opera nicht funktionierte. Dies war vor einem Jahr und ich hatte noch keine Gelegenheit, es erneut zu versuchen (ich habe damals ein Problem auf Github eröffnet, aber ich denke, sie haben die Probleme vor einiger Zeit zurückgesetzt). Wenn dies behoben ist (oder Sie diese Browser nicht mögen), verwenden Sie auf jeden Fall die Antwort von Chris! Wenn jemand es ausprobieren und die Antwort kommentieren / bearbeiten kann, noch besser.
Mna
1
@PuerkitoBio - Ich kann bestätigen, dass für IE8 und darunter noch $event.preventDefault()... IE-Steuer erforderlich ist .
Scotty.NET
4
Wenn Sie das $ -Ereignis an den Controller übergeben, verweisen Sie auf das DOM in Ihrem Controller. Dies bedeutet, dass Sie Ihre Ansicht und Ihren Controller gekoppelt haben. Sie können $ event-Methoden direkt in Ihrem ausgewerteten Ausdruck aufrufen: ng-click="do(); $event.preventDefault()Zum Beispiel ... obwohl dies nicht erforderlich ist, da die Antwort von @ Chris unten die richtige ist. Dies kann Personen in Situationen helfen, in denen sie ngClicks verschachtelt haben und aufrufen möchten $event.stopPropagation().
Ben Lesh
2
Endlich eine SEO-freundliche Lösung. Möglicherweise möchten Sie auch die Browser-URL aktualisieren, ohne die ng-Ansicht neu zu laden - joelsaupe.com/programming/…. Auf diese Weise haben Sie Links, die Ihre Ansicht nicht neu laden, aber in einem neuen Tab geöffnet werden können, und Suchmaschinen können ihnen folgen. YAY!
Tom
111

Ich bevorzuge es, Anweisungen für solche Dinge zu verwenden. Hier ist ein Beispiel

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

Und der Direktivencode für eat-click:

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

Jetzt können Sie das eat-clickAttribut jedem Element hinzufügen und es wird preventDefault()automatisch bearbeitet.

Leistungen:

  1. Sie müssen das hässliche $eventObjekt nicht an Ihre do()Funktion übergeben.
  2. Ihr Controller kann besser auf Einheiten getestet werden, da das $eventObjekt nicht ausgeblendet werden muss
DJsmith
quelle
1
@Kato Angular wird mit einer eigenen Untergruppe von jQuery geliefert, um unser Leben einfacher zu machen.
Neil
3
Zusätzlicher Vorteil - dies funktioniert auch in IE8 und darunter, wenn dies für Sie von Bedeutung ist.
Scotty.NET
1
Ich bekomme Error: $ is not defined. Was vermisse ich?
Bilal Mirza
7
Ich habe es versucht angular.element(element).bind('click', function(event){...});. Es funktionierte. Ref: jQLite
Bilal Mirza
3
Die Einführung einer Direktive für so etwas Einfaches scheint etwas aufgebläht zu sein, wenn Sie mich fragen ... Überprüfen Sie Chris seine Antwort unten
Wilt
54

Obwohl Renaud eine tolle Lösung gab

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

Ich persönlich habe festgestellt, dass Sie in einigen Fällen auch $ event.stopPropagation () benötigen, um einige der Nebenwirkungen zu vermeiden

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

wird meine Lösung sein

Zainengineer
quelle
34
ng-click="$event.preventDefault()"
Der Zauber von Oz
quelle
13
Dies ist die beste Lösung. Natürlich können Sie das $ event-Objekt auch an Ihre Bereichsfunktion übergeben. Wie ng-click = "myFunction ($ event, otherParams) und dann $ event.preventDefault () in myFunction. Das Rollen Ihrer eigenen Direktive dafür ist übertrieben
Charlie Martin
34

Die einfachste Lösung, die ich gefunden habe, ist diese:

<a href="#" ng-click="do(); $event.preventDefault()">Click</a>
Clément Renaud
quelle
Dies ist nicht nur die einfachste, sondern koppelt auch keine Ereignisse mit dem Controller, wie in anderen Lösungen vorgeschlagen. Das Koppeln von Ereignissen an einen Controller sollten Sie unbedingt vermeiden, da dies das Testen erheblich erschwert.
Jornare
11

Wenn Sie diese Antworten durchlesen, hat @Chris immer noch die "richtigste" Antwort, aber es gibt ein Problem: Der "Zeiger" wird nicht angezeigt.

Es gibt also zwei Möglichkeiten, um dieses Problem zu lösen, ohne einen Cursor hinzufügen zu müssen: Zeigerstil:

  1. Verwenden Sie javascript:void(0)anstelle von #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
  2. Verwendung $event.preventDefault()in der ng-clickDirektive (damit Sie Ihren Controller nicht mit DOM-bezogenen Referenzen überladen):

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

Ich persönlich bevorzuge das erstere gegenüber dem letzteren. javascript:void(0)hat andere Vorteile, die hier diskutiert werden . Es gibt auch eine Diskussion über "unauffälliges JavaScript" in diesem Link, der erschreckend neu ist und nicht unbedingt direkt auf eine Winkelanwendung zutrifft.

Ben Lesh
quelle
2
Warum wird das abgelehnt? Mir ist auch aufgefallen, dass der Zeiger bei der Antwort von Chris nicht angezeigt wird.
Wim Deblauwe
2
Javascript: void (0) ist viel besser als #, was auf die Route einwirken kann, wenn Sie sie falsch konfigurieren. +1
Shay Elkayam
2
Ich wollte gerade eine Antwort darauf schreiben. Sie können auch tunjavascript:;
Adrian
10

Sie können wie folgt vorgehen

1.Entfernen Sie das hrefAttribut vom anchor ( a) -Tag

2. Setzen Sie den Zeigercursor in CSS auf ng click-Elemente

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

HTML

hier pure anglejs: In der Nähe der ng-click-Funktion können Sie die Funktion prepareDefault () schreiben, indem Sie das Semikolon trennen

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

JS

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

(oder)

Sie können so vorgehen, dies wird hier bereits besprochen.

HTML

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

JS

$scope.do = function(event) {
    event.preventDefault();
    event.stopPropagation()
}
vallepu veerendra kumar
quelle
7

Versuchen Sie diese Option, die ich sehen kann, ist oben noch nicht aufgeführt:

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

Warum benötigen Sie Links, da Sie eine Web-App erstellen?

Tauschen Sie Ihre Anker gegen Knöpfe!

<button ng-click="do()"></button>
Sidonaldson
quelle
2
Da wen können Webapps keine Anker haben?
Robin van Baalen
1
Ich bezog mich auf den Punkt, dass die meisten Web-Apps keine relativen Links benötigen, wie dies bei Websites der Fall ist. Außerdem verwenden sie häufig nur Ankerlinks als Javascript-Trigger und verlinken nicht auf eine Seite. Daher ist eine Schaltfläche mit dem Standard-Stil-Reset genauso semantisch korrekt, wenn nicht mehr.
Sidonaldson
3
@sidonaldson Tatsächlich hängen heutzutage viele Web-Apps stark von Links ab. Schauen Sie sich Angularjs Routing an.
Robert
1
@Robert ja, aber wenn Sie das eingebaute Routing verwenden, müssen Sie nicht verhindern, dass Standard, es wird für Sie erledigt. Ich nehme an, da das Poster einen Ankerlink stornieren möchte, spricht er von Nicht-Routen-Links. Zum Beispiel das Starten eines
Modals
2
Diese Antwort sollte viel mehr positive Stimmen haben. In vielen Fällen verwenden Sie den Anker als Schaltfläche und nicht als Link, wenn Sie das Standardverhalten des Ankers verhindern möchten.
ItsCosmo
6

falls noch relevant:

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

...

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

...
xac
quelle
6

Der sicherste Weg, Ereignisse auf einer href zu vermeiden, besteht darin, sie als zu definieren

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

Ich würde gehen mit:

<a ng-click="do()">Click</a>
  • denn laut den Dokumenten sollten Sie in der Lage sein, die href zu verlassen, und dann wird Angular die Verhinderung der Standardeinstellung für Sie übernehmen!

Insgesamt war dies für mich verwirrend, daher habe ich dort eine JSFiddle erstellt, die zeigt, wann und wo Angular die Standardeinstellung verhindert .

Die JSFiddle verwendet Angulars Direktive - daher sollte sie genau gleich sein. Sie können den Quellcode hier sehen: einen Tag-Quellcode

Ich hoffe, dass dies für einige zur Klärung beiträgt.

Ich hätte das Dokument gerne bei ngHref gepostet, kann es aber aufgrund meines Rufs nicht.

Martinmose
quelle
5

Das mache ich immer. Klappt wunderbar!

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

Oder wenn Sie Inline benötigen, können Sie dies tun:

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

Viele Antworten scheinen übertrieben zu sein. Für mich funktioniert das

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

Ich benötige den Wert des href-Attributs für die Verschlechterung (wenn js ausgeschaltet ist), daher kann ich kein leeres href-Attribut (oder "#") verwenden, aber der obige Code hat bei mir nicht funktioniert, da ich ein Ereignis benötige ( e) variabel. Ich habe meine eigene Direktive erstellt:

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

In HTML:

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

Aus der Antwort von Tennisgent entlehnt. Ich finde es gut, dass Sie keine benutzerdefinierte Direktive erstellen müssen, um alle Links hinzuzufügen. Ich konnte ihn jedoch nicht dazu bringen, in IE8 zu arbeiten. Hier ist, was endlich für mich funktioniert hat (mit Angular 1.0.6).

Beachten Sie, dass Sie mit 'bind' jqLite verwenden können, das von angle bereitgestellt wird, sodass Sie nicht mit der vollständigen jQuery umbrechen müssen. Erforderlich ist auch die stopPropogation-Methode.

.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();
                    }
                })
            }
        };
    }
])
Lukus
quelle
3
Das tötet zu viel. Wenn ich beispielsweise Twitter-Bootstraps verwende dropdown, möchte ich die Weitergabe, aber nicht das Standardverhalten. Dieses Snippet wird NICHT empfohlen.
Robin van Baalen
2

Ich bin auf dasselbe Problem gestoßen, als ich Anker für ein eckiges Bootstrap-Dropdown verwendet habe. Die einzige Lösung, die ich gefunden habe, um unerwünschte Nebenwirkungen zu vermeiden (dh das Dropdown-Menü, das aufgrund der Verwendung von präventDefault () nicht geschlossen wurde), war die Verwendung der folgenden:

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

Wenn Sie niemals zu href gehen möchten, sollten Sie Ihr Markup ändern und eine Schaltfläche verwenden, die kein Ankertag ist, da es sich semantisch nicht um einen Anker oder einen Link handelt. Umgekehrt, wenn Sie eine Schaltfläche haben, die einige Überprüfungen durchführt und diese dann umleitet, sollte es sich um ein Link- / Anker-Tag und nicht um eine Schaltfläche handeln ... auch für SEO-Zwecke [Test-Suite hier einfügen].

Für Links, die Sie nur unter bestimmten Bedingungen umleiten möchten, z. B. die Aufforderung zum Speichern von Änderungen oder das Bestätigen des fehlerhaften Status ... sollten Sie ng-click = "someFunction ($ event)" und in someFunction für validationError verhindernDefault und / oder stopPropagation verwenden.

auch nur weil du kannst, heißt das nicht, dass du es solltest . Javascript: void (0) hat früher gut funktioniert ... aber wegen der schändlichen Hacker / Cracker-Browser kennzeichnen Apps / Websites, die Javascript in einem href verwenden ... siehe oben keinen Grund, sich zu ducken.

Es ist 2016, seit 2010 sollte es keinen Grund geben, Links zu verwenden, die wie Schaltflächen wirken. Wenn Sie IE8 und darunter noch unterstützen müssen, müssen Sie Ihren Geschäftssitz neu bewerten.

PDA
quelle
1
/* NG CLICK PREVENT DEFAULT */

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

quelle
1

Was Sie tun sollten, ist das hrefAttribut vollständig wegzulassen .

Wenn Sie sich den Quellcode für die aElementanweisung ansehen (die Teil des Angular-Kerns ist), heißt es in Zeile 29 - 31:

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

Das heißt, Angular löst bereits das Problem der Links ohne href. Das einzige Problem, das Sie noch haben, ist das CSS-Problem. Sie können den Zeigerstil weiterhin auf Anker mit ng-Klicks anwenden, z.

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

Sie können Ihre Website also sogar zugänglicher machen, indem Sie echte Links mit einem subtilen, anderen Stil als Links markieren, die Funktionen ausführen.

Viel Spaß beim Codieren!

Justus Romijn
quelle
1

Sie können die URL-Umleitung im Html5Mode von $ location deaktivieren, um das Ziel zu erreichen. Sie können es innerhalb des spezifischen Controllers definieren, der für die Seite verwendet wird. Etwas wie das:

app.config(['$locationProvider', function ($locationProvider) {
    $locationProvider.html5Mode({
        enabled: true,
        rewriteLinks: false,
        requireBase: false
    });
}]);

Strich
quelle
1

Wenn Sie Angular 8 oder höher verwenden, können Sie eine Direktive erstellen:

import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[preventDefault]'
})
export class PreventDefaultDirective {

  @HostListener("click", ["$event"])
  public onClick(event: any): void
  {
    console.log('click');
    debugger;
      event.preventDefault();
  }

}

Auf Ihrem Ankertag auf der Komponente können Sie es wie folgt verkabeln:

  <a ngbDropdownToggle preventDefault class="nav-link dropdown-toggle" href="#" aria-expanded="false" aria-haspopup="true" id="nav-dropdown-2">Pages</a>

App-Modul sollte seine Erklärung haben:

import { PreventDefaultDirective } from './shared/directives/preventdefault.directive';


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective
Raghav
quelle
-1

Eine Alternative könnte sein:

<span ng-click="do()">Click</span>
Terence Bandoian
quelle
1
Es ist eine schreckliche Praxis, a spanzum Klicken zu missbrauchen . Gehen Sie einfach zur Antwort von @ Tennisgent - Anker ohne hrefDefinition.
Robin van Baalen
1
@RobinvanBaalen Das span-Element wurde seit mindestens HTML 4.0.1 als anklickbar definiert: w3.org/TR/html401/struct/global.html#edef-SPAN w3.org/TR/html5/dom.html#global-attributes html.spec.whatwg.org/multipage/dom.html#global-attributes
Terence Bandoian
1
Wenn Sie <span> Hallo </ span> tun, seit wann ist das anklickbar? In der Spezifikation heißt es wahrscheinlich, dass ein <span> in einem anklickbaren Element wie <a> oder <button> verwendet werden kann. Andererseits können alle Inline-Blockelemente (img, span usw.) auf diese Weise anklickbar gemacht werden. Eine Spanne selbst kann nicht angeklickt werden.
Robin van Baalen
1
@RobinvanBaalen Bitte beachten Sie die obigen Links. Das onclick-Attribut für span-Elemente wurde seit mindestens HTML 4.01 definiert.
Terence Bandoian
1
Ich habe nie gesagt, dass das Hinzufügen eines Ereignishandlers für eine gewisse Zeit nicht funktionieren würde. Ich sagte, es sei eine schlechte Praxis, ein nicht anklickbares Element wie span, div, section, ul, li usw. mithilfe eines Javascript-Ereignishandlers anklickbar zu machen. Es geht nur um Semantik. Semantik in HTML ist die Praxis, dem Inhalt der Seite Bedeutung und Struktur zu geben, indem das richtige Element verwendet wird.
Robin van Baalen