1

I'm trying to create a directive that will disable all the input elements inside of the container, but I'm having trouble with the attribute. This is what I've got for the directive

Directive

angular.module('common')
    .directive('bdDisabled', [function () {
            return {
                restrict: 'A',
                scope: {
                    bdDisabled: '='
                },
                link: function (scope, element, attrs) {
                    attrs.$observe('bdDisabled', function(newValue, oldValue) {
                        if (newValue !== oldValue) {
                            if (newValue) {
                                element.find('input, select, button, submit, textarea').prop('disabled', 'disabled');
                            } else {
                                element.find('input, select, button, submit, textarea').removeProp('disabled');
                            }

                        }
                    });
                }
            };
        }
    ]);

This is how I want to use it:

<div class="cg-content cg-shadow" bd-disabled="isLoading">

The problem is that the attribute value is the string isLoading and not the value.

If I wrap it in braces it breaks and I get an error in the console. If I wrap it in braces and change the scope to '@' instead of '=', it works. But it sends the string "true" or "false", not a boolean value.

Where am I going wrong?

Smeegs
  • 9,151
  • 5
  • 42
  • 78

3 Answers3

1

As I suggested in the comment, I'd switch the attrs.$observe with scope.$watch. On a personal preference, I'd also use the function expression instead of a string, since if you're using typescript for instance (or will use) you'll be notified if the property changes, where a string will probably remain as it is:

scope.$watch(function () {
      return scope.bdDisabled;
      }, 
      function (newVal, oldVal) {
          ...
      }
);
Omri Aharon
  • 16,959
  • 5
  • 40
  • 58
  • Sorry but i don't see the relevance to using the function in your `$watch` and TypeScript? It's possible with or without. – ste2425 Mar 31 '16 at 15:41
  • 1
    @ste2425 What I said was that if you're using Typescript, for instance, and set a compiler to fail on build on JS errors, then changing the variable's name you're watching will cause the build to fail if you're referencing the variable in the function (since that variable will no longer be known). If it's just written in the string, i.e., 'bdDisabled', then compilation will still succeed. That was just an example. – Omri Aharon Mar 31 '16 at 16:32
  • $watch is used when you want to watch a model or scope property. E.g in your case bd-disabled="isLoading" , scope.$watch(attrs.bdDisabled) or scope.watch('isLoading') . $observe will only work when you want to watch value change of a DOM attribute using interpolation e.g firstName= "Mr : {{firstName}}" in your directive use attrs.$observe('firstName') in this case $scope.$watch won't work. – Venkat Mar 31 '16 at 17:14
-1

You don't have to use observe with '='. See the following link for details, I believe it is much more robust than the docs.

What is the difference between '@' and '=' in directive scope in AngularJS?

As far as your code goes, I would double check the isLoading variable to make sure it is a boolean.

Community
  • 1
  • 1
rabruce
  • 133
  • 1
  • 8
  • Hi, it's definitely a boolean. The reason it's being processed as a string is because of the `@`, which casts it as a string when passing it in. – Smeegs Mar 31 '16 at 15:38
  • @Smeegs my mistake, I was looking at your code when I read that. – rabruce Mar 31 '16 at 15:46
-1

When you changed you scope definition from "=" to "@", you just want to pass the as a String, not the Two-Way-Bind mode. Sure, you can convert that to true indeed, like:

var myBool = Boolean("false"); // === true

var myBool = Boolean("true"); // === true

But be careful with that because any string can be consider as true like:

var myBool = Boolean("foo"); // === true

Eduardo Pereira
  • 840
  • 1
  • 8
  • 19