How to preventDefault on anchor tags?

The question:

Let’s say I have an anchor tag such as

<a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" ng-click="do()">Click</a>

How can I prevent the browser from navigating to # in AngularJS ?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

According to the docs for ngHref you should be able to leave off the href or do 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=" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"value = 2">link 2</a> (link, don't reload)<br />
<a id="link-4" href="" name=" rel="nofollow noreferrer noopener"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 />

Method 2

UPDATE: I’ve since changed my mind on this solution. After more development and time spent working on this, I believe a better solution to this problem is to do the following:

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

And then update your css to have an extra rule:

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

Its much more simple and provides the exact same functionality and is much more efficient. Hope that might be helpful to anyone else looking up this solution in the future.


The following is my previous solution, which I am leaving here just for legacy purposes:

If you are having this problem a lot, a simple directive that would fix this issue is the following:

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

It checks all anchor tags (<a></a>) to see if their href attribute is either an empty string ("") or a hash ('#') or there is an ng-click assignment. If it finds any of these conditions, it catches the event and prevents the default behavior.

The only down side is that it runs this directive for all anchor tags. So if you have a lot of anchor tags on the page and you only want to prevent the default behavior for a small number of them, then this directive isn’t very efficient. However, I almost always want to preventDefault, so I use this directive all over in my AngularJS apps.

Method 3

You can pass the $event object to your method, and call $event.preventDefault() on it, so that the default processing will not occur:

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

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

Method 4

I prefer to use directives for this kind of thing. Here’s an example

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

And the directive code for eat-click:

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

Now you can add the eat-click attribute to any element and it will get preventDefault()‘ed automagically.

Benefits:

  1. You don’t have to pass the ugly $event object into your do() function.
  2. Your controller is more unit testable because it doesn’t need to stub out the $event object

Method 5

Although Renaud gave a great solution

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

I personally found you also need $event.stopPropagation() in some cases to avoid some of the side effects

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

will be my solution

Method 6

The easiest solution I have found is this one :

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

Method 7

ng-click="$event.preventDefault()"

Method 8

So reading through these answers, @Chris still has the most “correct” answer, I suppose, but it has one problem, it doesn’t show the “pointer”….

So here are two ways to solve this problem without needing to add a cursor:pointer style:

  1. Use javascript:void(0) instead of #:

    <a href="javascript:void(0)" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" ng-click="doSomething()">Do Something</a>
    
  2. Use $event.preventDefault() in the ng-click directive (so you don’t junk up your controller with DOM-related references):

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

Personally I prefer the former over the latter. javascript:void(0) has other benefits that are discussed here. There is also discussion of “unobtrusive JavaScript” in that link which is frighteningly recent, and doesn’t necessarily directly apply to an angular application.

Method 9

You can do as follows

1.Remove href attribute from anchor(a) tag

2.Set pointer cursor in css to ng click elements

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

Method 10

HTML

here pure angularjs: near to ng-click function you can write preventDefault() function by seperating semicolon

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

JS

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

(or)

you can proceed this way, this is already discussed some one here.

HTML

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

JS

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

Method 11

Since you are making a web app why do you need links?

Swap your anchors to buttons!

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

Method 12

Try this option which I can see is not yet listed above :

<a href="" ng-click=" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"do()">Click</a>

Method 13

if still relevant:

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

...

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

...

Method 14

The safest way to avoid events on an href would be to define it as

<a href="javascript:void(0)" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" ....>

Method 15

I would go with:

<a ng-click="do()">Click</a>
  • because according to the docs you should be able to leave of the href and then Angular will handle the prevent default for you!

Whole this prevent default thing has been confusing to me, so I have created a JSFiddle
there illustrate when and where Angular is preventing default
.

The JSFiddle is using Angular’s a directive – so it should be EXACTLY the same. You can see the source code here: a tag source code

I hope this will help clarification for some.

I would have liked to post the doc to ngHref but I can’t because of my reputation.

Method 16

This is what I always do. Works like a charm!

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

Method 17

Or if you need inline then you can do this:

<a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" ng-click="show = !show; $event.preventDefault()">Click to show</a>

Method 18

Lot of answers seem to be overkill. FOR ME , this works

 <a ng-href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" ng-click="$event.preventDefault();vm.questionContainer($index)">{{question.Verbiage}}</a>

Method 19

I need a presence of href attribute’s value for degradation (when js is switched off), so I can’t use empty href attribute (or “#”), but the code above did not work for me, because i need an event (e) variable. I created my own directive:

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" rel="nofollow noreferrer noopener" ng-click="openSignUpModal()">Sign up</a>

Method 20

Borrowing from tennisgent’s answer. I like that you don’t have to create a custom directive to add on all the links. However, I couldnt get his to work in IE8. Here’s what finally worked for me (using angular 1.0.6).

Notice that ‘bind’ allows you to use jqLite provided by angular so no need to wrap with full jQuery. Also required the stopPropogation method.

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

Method 21

I ran into this same issue when using anchors for an angular bootstrap drop down. The only solution I found that avoided unwanted side effects (ie. the drop down not closing because of using preventDefault()) was to use the following:

 <a href="javascript:;" rel="nofollow noreferrer noopener" ng-click="do()">Click</a>

Method 22

if you never want to go to href… you should change your markup and use a button not an anchor tag because semantically it’s not an anchor or a link. Inversely if you have a button that does some checks and then redirects it should be a link / anchor tag and not a button… for SEO purposes as well testing [insert test suite here].

for links that you only want to redirect conditionally like prompting to save changes, or acknowledge dirty state… you should use ng-click=”someFunction($event)” and in someFunction on your validationError preventDefault and or stopPropagation.

also just because you can doesn’t mean you should. javascript:void(0) worked well back in the day… but because of the nefarious hackers/crackers browsers flag apps/sites that use javascript within an href… see no reason to ducktype above..

it’s 2016 since 2010 should be no reason anywhere to use links that act like buttons… if you still have to support IE8 and below you need to re-evaluate your place of business.

Method 23

If you are using Angular 8 or more you can create a directive:

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

}

On your anchor tag on the component you can wire it like this:

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

App Module should have its declaration:

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


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective

Method 24

/* NG CLICK PREVENT DEFAULT */

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

Method 25

What you should do, is omit the href attribute entirely.

If you look at the source code for the a element directive (which is a part of the Angular core), it states at line 29 – 31:

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

Which means Angular already is solving the issue of links without a href. The only issue you still have is the css problem. You can still apply the pointer style to anchors that have ng-clicks, e.g.:

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

So, you could even make your site more accessible by marking real links with a subtle, different styling then links that perform functions.

Happy coding!

Method 26

You can disable url redirection inside $location’s Html5Mode to achieve the objective. You can define it inside the specific controller used for the page.
Something like this:

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

Method 27

In my case Angular: 10 – work this

  <a [routerLink]="" (click)="myFunc()"> Click me </a>

Updated: This approach will reload the resolvers. Thanks @Meeker

Method 28

An alternative might be:

<span ng-click="do()">Click</span>


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment