Angular's framework automatically creates an internal ng-attribute Alias directive for all boolean attribute equivalents like
ng-required, ng-checked, ng-disabled
, and more.
Source
var BOOLEAN_ATTR = {};
forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
BOOLEAN_ATTR[lowercase(value)] = value;
});
The generic link function registered on these attributes performs a toggling action.
Source
forEach(BOOLEAN_ATTR, function(propName, attrName) {
// binding to multiple is not supported
if (propName == "multiple") return;
function defaultLinkFn(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
}
var normalized = directiveNormalize('ng-' + attrName);
var linkFn = defaultLinkFn;
if (propName === 'checked') {
linkFn = function(scope, element, attr) {
// ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
if (attr.ngModel !== attr[normalized]) {
defaultLinkFn(scope, element, attr);
}
};
}
ngAttributeAliasDirectives[normalized] = function() {
return {
restrict: 'A',
priority: 100,
link: linkFn
};
};
});
Essentially, ng-required
adds the attribute required
, which is internally registered as a directive that handles validation for ng-model
.
You can confirm this by examining the contents of the ngRequired
directive, which includes two configurations - one for setting/resetting attributes and another for validation with ng-model
and validators.
.config(function($provide) {
$provide.decorator('ngRequiredDirective', function($delegate) {
console.log($delegate); //Check the console on the configuration you will see array of 2 configurations
return $delegate;
})
});
This concept is similar to creating multiple configurations for the same directive selector:
angular.module('app', []).directive('myDir', function() {
return {
restrict: 'A',
link: function() {
console.log("A");
}
}
}).directive('myDir', function() {
return {
restrict: 'A',
link: function() {
console.log("B");
}
}
}).config(function($provide) {
$provide.decorator('myDirDirective', function($delegate) {
console.log($delegate); //Check the console on the configuration you will see array of 2 configurations
return $delegate;
})
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app">
<div my-dir></div>
</div>