Material: Not able to ng-disable in link function (md-datepicker)

Created on 18 Oct 2016  路  18Comments  路  Source: angular/material

When manipulating the disabled attribute, the input style changes but the icons are still clickable.
I am changing the attribute value in a watcher in the link function. To clarify my statement please see this example code:

Template:

<md-input-container group="groupname" is-key="false" my-group-input>
    <md-datepicker ng-model="myDate" md-placeholder="Enter date"></md-datepicker>
</md-input-container>

Link function of attribute directive

function exampleDirective($exampleFactory) {
    return {
        restrict: 'A',
        scope: {
            isKey: '=',
            group: '@',
        },
        controller: MyGroupInputController,
        link: function(scope, element, attr) {
            var inputElement = element.find('md-datapicker');

            scope.$watch(function () {
                    return $exampleFactory.InputItems;
                }, function (newval, oldval) {
                    if (newval[attr.group].isEmpty === true) {
                        inputElement.attr('disabled', 'disabled');
                       // inputElement.attr('ng-disabled', 'true'); doesn't work
                    } else {
                        inputElement.removeAttr('disabled');
                        //inputElement.attr('ng-disabled', false);
                    }
                }, true);
            }
        }
   }

Expected behavior is:
image

Actual behavior is:
image

Setting inputElement.attr('ng-disabled', 'true'); seems to work when I inspect the page:
image

But doesn't affect the md-datepicker

How wil I be able to change the ng-disabled of the md-datepicker?

feedback bug

Most helpful comment

Here's what I mean @Dennisoost: http://codepen.io/crisbeto/pen/rMEgBJ?editors=0010

Or if you want it even better, you can do this. This avoids having to deal with $compile directly: http://codepen.io/crisbeto/pen/QKXRwd?editors=0010

All 18 comments

@topherfangio - let's make sure we are consistent with the way other components use disabled, ng-disabled, etc.

@Dennisoost ng-disabled should work, however you should keep in mind that the linking phase (which you're using) happens after the datepicker has been set up. This means that the datepicker won't watch for the disabled attribute since it wasn't there during compilation. To work around this, you've got two options:

  1. Set a ng-disabled expression to your datepicker either directly in the template, or in a compile block.
  2. If option 1 isn't feasible, you can get a hold of the datepicker's controller and use the setDisabled method to toggle it manually. Here's how your example could be rewritten:
function exampleDirective($exampleFactory) {
  return {
    restrict: 'A',
    scope: {
      isKey: '=',
      group: '@',
    },
    controller: MyGroupInputController,
    link: function(scope, element, attr) {
      var datepickerCtrl = element.find('md-datapicker').controller('mdDatepicker');

      scope.$watch(function() {
        return $exampleFactory.InputItems;
      }, function(newval) {
        datepickerCtrl.setDisabled(newval[attr.group].isEmpty === true);
      }, true);
    }
  };
}

Let me know if you have any questions.

This issue is closed as it falls in the 'deprecated' category. We deprecate issues for one or more of the following reasons:

  • Issue has a reasonable workaround
  • Issue doesn't have a demo or reproducible case available
  • Issue is real, but fixing it is risky for users who depend on existing behavior
  • Issue is real, but only affects a very small use case
  • Issue is real, but would require significant work to fix, and is less urgent than other needs.

Pull Requests are welcomed to resolve this issue. But note that not all community PRs will be merged into master. Pull Requests with large changes or large scope impacts will probably be rejected [due to stability risks to existing users].

@crisbeto I tried solution 1 before and can't seem to get it to work. Solution 2 fixed it for me! thanks! Can you point me to the documentation regarding the .controller() method and the setDisabled() method? I can't seem to find those.

So for the datepicker it is working, but for md-select it says that the 'setDisabled is not a function'.

@Dennisoost Solution 2 isn't documented, because it's a part of the internal datepicker API. .controller returns the controller of the md-datepicker directive which then lets you use the internal API directly, however that doesn't mean that other components would implement it in the same way. The recommended way of doing this is option 1, however that wasn't feasible in your particular case (adding the ng-disabled attribute in the linking phase).

@crisbeto ah ok, makes sense. I just tried solution 1 again, with adding a ng-disabled directly to the template and I also tried to add ng-disabled in the compile function, but both have the same effect. The values seem to change when I inspect the DOM, but no changes to the styling of the component.

Currently I fixed this by getting the separate elements of the md-components in the link function, and adding a disable attribute to these elements. It works, but it feels like a unclean fix.

Thanks for your help

Alright, then it sounds like a bug. I'll follow this up later.

@Dennisoost - please provide a working CodePen that demonstrates the issue; and will be used to validate any fixes.

@Dennisoost I wasn't able to reproduce it. It worked fine both when using only disabled on load and using ng-disabled to toggle it dynamically. Here's a codepen. I'll close this since it looks like everything works as expected, but we can continue the discussion.

@crisbeto I will make a codepen in one of the coming days.

@crisbeto While making a codepen I got a bit carried away and spend some time trying to fix my problem. So eventually I found that I had to compile the html element and bind it to the scope. (I think you said something like this in your first comment, wasn't clear for me since I wasn't familair with the $compile service).

See: http://codepen.io/dennisoost/pen/XjLemB

Thanks for you help, this issue is closed for me.

Yes, if you're adding the ng-disabled expression at a later point, you need to recompile your element. Note that what you're doing in your codepen is a bad way of using $compile since you're recompiling the element for every time your expression changes. Instead you should only do it once when the link function runs.

@crisbeto
http://codepen.io/dennisoost/pen/rMEQpa

I think this is what you mean? But this doesn't work for me.

Here's what I mean @Dennisoost: http://codepen.io/crisbeto/pen/rMEgBJ?editors=0010

Or if you want it even better, you can do this. This avoids having to deal with $compile directly: http://codepen.io/crisbeto/pen/QKXRwd?editors=0010

@crisbeto
Yes, eventually I found out. This works great for almost all input elements except md-select
see: http://codepen.io/dennisoost/pen/qazGag

image

Yeah, md-select is pretty complicated and I'm not too familiar with the way it's set up.

@crisbeto
Your second codepen works (also on the md-select!), it isn't clear for me why though. To me it seems like the set of the attribute is dependent on something you add later in the postLink.

Anyway thanks for your patience and your help.

@crisbeto still stuck on one small thing. When using a scope in a directive the factoryRef is somehow not set. See: http://codepen.io/dennisoost/pen/Wovdyy

Edit: I fixed this by removing the:

scope: {
iskey: '='
}

And by getting the attribute values like this:

 compile: function(tElement, tAttrs){
     var myAttr = tAttrs.iskey
     ...
}    
Was this page helpful?
0 / 5 - 0 ratings