Search code examples
angularjsangularjs-directiveangularjs-ng-disabled

ng-disabled inside custom directive isn't working


I'm trying to implement a custom directive that forces the user to hold a button instead of just clicking it, preventing numerous mistakes. A material design slider is present under the button to show how long the user has to click on the button.

But sometimes, there has to be moments where the button must not be clickable, for example if there is a form with incorrect values. I tried to set the ng-disabled attribute but nothing is working. What am I doing wrong ?

Js :

negoceExpedApp.directive('rkMouseHold', function ($interval, $timeout) {
    return {
        restrict: 'E',
        scope: {
            text: '=buttonText',
            callback: '&callback',
            isDisabled: '&isDisabled'
        },
        replace: true,
        template: "<div style='width:fit-content'>" +
            "<md-button ng-disabled='{{disabled}}' class='md-accent md-raised md-hue-400'>{{ text }} - {{ disabled }}</md-button><br>" +
            "<md-progress-linear ng-show='c!=0' class='md-accent md-hue-400' md-mode='determinate' value='{{c/10}}'></md-progress-linear>" +
            "</div>",
        link: function (scope, element, attrs) {
            scope.$watch(scope.isDisabled,(newVal)=>{
                console.log("%c newVal","color:orange",newVal);
                if(newVal==true){
                    scope.disabled = "true";
                } else {
                    scope.disabled = 'false';
                }
            })
            scope.c = 0;
            scope.loop = null;
            element.on('mousedown', () => {
                scope.loop = $interval(function () {
                    $timeout(() => {
                        scope.c += 100
                    }, 0);
                }, 100);
            });

            element.on('mouseup', () => {
                $interval.cancel(scope.loop);
                if (scope.c > 1000) {
                    scope.callback();
                }
                scope.c = 0;
            })
        }
    }
})

Html :

<rk-mouse-hold callback="ctrl.saveForm()"
               is-disabled="expedForm.$invalid"
               button-text="'HOLD TO SAVE'">
</rk-mouse-hold>

Solution

  • ngDisabled is just a wrap-up for regular disabled directive, that supports interpolation. Now here how you setting disabled value

       if(newVal==true){
            scope.disabled = "true";
        } else {
            scope.disabled = 'false';
        }
    

    can be simplified to

      scope.disabled = !!newVal;
    

    And in the template

    ERRONEOUS

    <md-button ng-disabled='{{disabled}}' class='md-accent md-raised md-hue-400'>
        {{ text }} - {{ disabled }}
    </md-button><br>"
    

    use ng-disabled='disabled' instead of ng-disabled='{{disabled}}'

    In this case you are passing exact boolean value, while what you doing - each time you are passing string value, which is considered as true.

    After all, in your scope you defined your custom disabled like so

    isDisabled: '&isDisabled'
    

    & is used for evaluated expressions or callback, if you want to pass a variable. Checkout this great article as for correct bindings, and replace your code to

    isDisabled: '@'