Reputation: 161
Recently I have to make a Input element work with both ng-disabled and an custom directive which use isolated scope to evaluate expression just like what ng-disabled is doing, somehow, the custom directive works fine but ng-disabled doesn't, since it only evaluate expression within the isolated scope.
The custom directive is quite simple like:
angular
.module('directives', [])
.directive('conditionalAutofocus', function () {
return {
restrict:'A',
scope:{
condition:'&conditionalAutofocus'
},
link:function (scope, element, attrs) {
if (scope.condition()) {
attrs.$set('autofocus','true');
}
}
}
});
while the page looks like:
<input name="pin"
ng-model="pin"
type="password"
required
ng-disabled="names == null"
conditional-autofocus="names != null" />
Anybody already has solution for this issue?
Thanks in advance! Yanni
Upvotes: 14
Views: 19382
Reputation: 6248
You don't need any of the complexity of the other answers. The problem is that your Directive doesn't even know wtf ng-Disabled is. If you want to use ng-Disabled in your template, you have to inject it into your scope or requirements. For example, this Will NOT work:
.directive('myDirective', function () {
return {
restrict: 'E',
template: '<input type="text" ng-disabled="fieldDisabled" />',
scope:{ something: '=' },
link: function (scope, element, attrs) {
scope.something = attrs.something;
},
controller: function($scope) {
$scope.fieldDisabled = false;
$scope.myAction = function() {
$scope.fieldDisabled = true;
};
}
}
});
But the following Will work:
.directive('myDirective', function () {
return {
restrict: 'E',
template: '<input type="text" ng-disabled="fieldDisabled" />',
scope:{ something: '=', lol: '=ngDisabled' },
link: function (scope, element, attrs) {
scope.something = attrs.something;
},
controller: function($scope) {
$scope.fieldDisabled = false;
$scope.myAction = function() {
$scope.fieldDisabled = true;
};
}
}
});
Note that the only change is lol: '=ngDisabled'
. That makes it work because now your directive knows what ngDisabled is. You don't have to use lol
or do any other special wiring. You can use your controller just like any other controller now with your own variables.
Upvotes: 0
Reputation: 6237
I had this same issue, and the easiest solution imho. is to use the isolated scope to inherit the property of ngDisabled.
angular.module('directives', [])
.directive('conditionalAutofocus', function () {
return {
restrict:'A',
scope:{
condition:'&conditionalAutofocus',
disabled:'=ngDisabled'
},
link:function (scope, element, attrs) {
if (scope.condition()) {
attrs.$set('autofocus','true');
}
if(scope.disabled){
//is disabled
}
}
}
});
Might only work for restrict : 'E'. Have not tested others
Upvotes: 20
Reputation: 228
You can set up a bi-directional binding to the parent scope in your isolated scope definition. Then add a watch on the isolated scope property. This just duplicates the code in the ngReadonly directive.
angular.module('directives', [])
.directive('conditionalAutofocus', function () {
return {
restrict:'A',
scope:{
condition: '&conditionalAutofocus',
isReadonly: '=ngReadonly'
},
link:function (scope, element, attrs) {
if (scope.condition()) {
attrs.$set('autofocus','true');
}
scope.$watch('isReadonly', (value) => {
attrs.$set('readonly', !!value);
});
}
}
});
Upvotes: 1
Reputation: 2052
I had a similar problem lately. I wanted to disable a button in isolated scope and use this nice angular ng-disabled
directive.
After some digging I came to a solution like this:
link: function($scope, element, attrs){
$scope.$parent.$watch(attrs.ngDisabled, function(newVal){
element.prop('disabled', newVal);
});
//...
}
To evaluate the ng-diabled
expression instead of $scope
just jump to $scope.$parent
and all your variables will be avaliable. Unfortunatly manually setting the disabled property is required.
Upvotes: 4
Reputation: 161
OK, for my own case above my solution is to change the implementation of directive, not use isolated scope anymore:
angular.module('directives', [])
.directive('conditionalAutofocus', function () {
return {
restrict:'A',
link:function (scope, element, attrs) {
scope.$watch(attrs.conditionalAutofocus, function(){
if (scope.$eval(attrs.conditionalAutofocus)) {
element.focus();
}else{
element.blur();
}
});
}
}
});
Upvotes: 2