Enable/Disable Anchor Tags using AngularJS

131,141

Solution 1

Update: Disabling the href works better in the link function return. Code below has been updated.

aDisabled naturally executes before ngClick because directives are sorted in alphabetical order. When aDisabled is renamed to tagDisabled, the directive does not work.


To "disable" the "a" tag, I'd want the following things:

  1. href links not to be followed when clicked
  2. ngClick events not to fire when clicked
  3. styles changed by adding a disabled class

This directive does this by mimicking the ngDisabled directive. Based on the value of a-disabled directive, all of the above features are toggled.

myApp.directive('aDisabled', function() {
    return {
        compile: function(tElement, tAttrs, transclude) {
            //Disable ngClick
            tAttrs["ngClick"] = "!("+tAttrs["aDisabled"]+") && ("+tAttrs["ngClick"]+")";

            //return a link function
            return function (scope, iElement, iAttrs) {

                //Toggle "disabled" to class when aDisabled becomes true
                scope.$watch(iAttrs["aDisabled"], function(newValue) {
                    if (newValue !== undefined) {
                        iElement.toggleClass("disabled", newValue);
                    }
                });

                //Disable href on click
                iElement.on("click", function(e) {
                    if (scope.$eval(iAttrs["aDisabled"])) {
                        e.preventDefault();
                    }
                });
            };
        }
    };
});

Here is a css style that might indicate a disabled tag:

a.disabled {
    color: #AAAAAA;
    cursor: default;
    pointer-events: none;
    text-decoration: none;
}

And here is the code in action, with your example

Solution 2

My problem was slightly different: I have anchor tags that define an href, and I want to use ng-disabled to prevent the link from going anywhere when clicked. The solution is to un-set the href when the link is disabled, like this:

<a ng-href="{{isDisabled ? '' : '#/foo'}}"
   ng-disabled="isDisabled">Foo</a>

In this case, ng-disabled is only used for styling the element.

If you want to avoid using unofficial attributes, you'll need to style it yourself:

<style>
a.disabled {
    color: #888;
}
</style>
<a ng-href="{{isDisabled ? '' : '#/foo'}}"
   ng-class="{disabled: isDisabled}">Foo</a>

Solution 3

For people not wanting a complicated answer, I used Ng-If to solve this for something similar:

<div style="text-align: center;">
 <a ng-if="ctrl.something != null" href="#" ng-click="ctrl.anchorClicked();">I'm An Anchor</a>
 <span ng-if="ctrl.something == null">I'm just text</span>
</div>

Solution 4

Modifying @Nitin's answer to work with dynamic disabling:

angular.module('myApp').directive('a', function() {
  return {
    restrict: 'E',
    link: function(scope, elem, attrs) {
      elem.on('click', function(e) {
        if (attrs.disabled) {
          e.preventDefault(); // prevent link click
        }
      });
    }
  };
});

This checks the existence of disabled attribute and its value upon every click.

Solution 5

Disclaimer:

The OP has made this comment on another answer:

We can have ngDisabled for buttons or input tags; by using CSS we can make the button to look like anchor tag but that doesn't help much! I was more keen on looking how it can be done using directive approach or angular way of doing it?


You can use a variable inside the scope of your controller to disable the links/buttons according to the last button/link that you've clicked on by using ng-click to set the variable at the correct value and ng-disabled to disable the button when needed according to the value in the variable.

I've updated your Plunker to give you an idea.

But basically, it's something like this:

 <div>
       <button ng-click="create()" ng-disabled="state === 'edit'">CREATE</button><br/>
       <button ng-click="edit()" ng-disabled="state === 'create'">EDIT</button><br/>
       <button href="" ng-click="delete()" ng-disabled="state === 'create' || state === 'edit'">DELETE</button>
    </div>
Share:
131,141
John Smith
Author by

John Smith

Updated on July 09, 2022

Comments

  • John Smith
    John Smith almost 2 years

    How do I enable/disable anchor tags using the directive approach?

    Example:

    1. while clicking on edit link, create & delete needs to be disabled or grayed out
    2. while clicking on create link, edit & delete needs to be disabled or grayed out

    JAVASCRIPT:

        angular.module('ngApp', []).controller('ngCtrl',['$scope', function($scope){
    
        $scope.create = function(){
          console.log("inside create");
        };
    
        $scope.edit = function(){
          console.log("inside edit");
        };
    
        $scope.delete = function(){
        console.log("inside delete");
        };
    
        }]).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();
                            if(attrs.ngClick){
                                scope.$eval(attrs.ngClick);
                            }
                        });
                    }
                }
           };
        }); 
    

    LINK to CODE

  • John Smith
    John Smith about 10 years
    We can have ngDisabled for buttons or input tags; by using CSS we can make the button to look like anchor tag but that doesn't help much! I was more keen on looking how it can be done using directive approach or angular way of doing it?
  • ryeballar
    ryeballar about 10 years
    The title suggests an anchor tag, not a button.
  • Julien
    Julien about 10 years
    @ryeballar Did you read the comment made by the OP on the other answer ?
  • Wasmoo
    Wasmoo over 9 years
    It prevents ng-click from firing when a-disabled is false. It does this by changing the function before it gets processed, effectively turning <a ng-click="doSomething()" a-disabled="isDisabled()"> into <a ng-click="!isDisabled() && doSomething()">
  • Kenneth Sundqvist
    Kenneth Sundqvist over 9 years
    Yes, I understand that line as a whole. But I'm specifically wondering about the part that I isolated in my comment. (a, b) will execute both expression a and b but only return the value of b. In this case expression a is a string, so my understanding is that it's redundant. I left it out when I used this directive and it's still working as expected.
  • Wasmoo
    Wasmoo over 9 years
    I must have grabbed that bit of code from something else and let it go because I didn't understand the Javascript Comma Operator. I agree, it can safely be removed.
  • Marwen Trabelsi
    Marwen Trabelsi about 9 years
    @Julien : you have to mention in the top of your response that you answered the comment rather than the original question.
  • Julien
    Julien about 9 years
    @SmartyTwiti Done. Could you remove your downvote now?
  • Shannon Hochkins
    Shannon Hochkins almost 9 years
    For those who might want to perform a different task if it's disabled, simply add this if (angular.isDefined(iAttrs["aOnDisabledClick"])) scope.$eval(iAttrs["aOnDisabledClick"]); before e.preventDefault() and then add the a-on-disabled-click attribute to your anchor and parse it a function in that scope.
  • DrB
    DrB over 8 years
    Ng-diabled won't work for tag a as the tag itself does not accept such attribute.
  • z0r
    z0r over 8 years
    @BehnazChangizi It works, but may not be future-proof. I added an example that uses a class instead.
  • jemiloii
    jemiloii about 8 years
    This is completely future proof, all he is doing is creating an empty href if the link is disabled.
  • Coderer
    Coderer over 7 years
    It's a pretty bad habit to put navigation in a click event -- you can't (for example) open a page in a new tab/window if you don't express links as, well, links.
  • iiminov
    iiminov over 7 years
    @Coderer Perhaps you would like to add an example demonstrating a better way to handle this usecase?
  • Coderer
    Coderer over 7 years
    The two highest rated answers already use href manipulation instead of click events. And I should clarify: if you want a "do something" button, click events are fine, but use a <button>. If you want a "go somewhere" link, use <a href=...> but make the href meaningful.
  • iiminov
    iiminov over 7 years
    @Coderer I totally agree with you. But you have to take into account the way the original question is phrased How do I enable/disable anchor tags. I provided another possibility of how I enable/disable clicks on a <div> tag when a condition is met. And in my case, I had to use a <div> tag because of dependency on third party module. It is fair to point that this approach is not the best if you need to navigate somewhere but as demonstrated there is nothing stopping you from doing so.
  • Isaac Gregson
    Isaac Gregson over 7 years
    Note that pointer-events: none; disables the event from firing. Thus, in such cases, there's no need to disable it via JS (e.preventDefault();). Browser support is good (caniuse.com/#feat=pointer-events).
  • Isaac Gregson
    Isaac Gregson over 7 years
    Also, to prevent increased CSS specificity, I prefer to simply use [disabled] { pointer-events: none; }...
  • Shadow The Kid Wizard
    Shadow The Kid Wizard over 7 years
    Yeah, that's what I'm doing myself. Not very elegant but simple and useful. :)
  • Pierre Chavaroche
    Pierre Chavaroche about 7 years
    Good idea! And I think if (attrs.disabled) should be enough.
  • Felipe Leão
    Felipe Leão about 7 years
    You should invert the order between the check on disabledand the elem.on('click') redefinition.
  • Nitin...
    Nitin... about 7 years
    Fewer events, better performance, disabled anchors will always be a subset on all anchors
  • Salman Lone
    Salman Lone almost 7 years
    what if someone wants to show the <a> tag but disabled.