whole_func_string: function(elem, attr) {
        if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
  
        var shape = getShape(attr, elem);
  
        return {
          post: function(scope, elem, attr, ngModel) {
            var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
  
            function ngAriaWatchModelValue() {
              return ngModel.$modelValue;
            }
  
            function getRadioReaction(newVal) {
              // Strict comparison would cause a BC
              // eslint-disable-next-line eqeqeq
              var boolVal = (attr.value == ngModel.$viewValue);
              elem.attr('aria-checked', boolVal);
            }
  
            function getCheckboxReaction() {
              elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
            }
  
            switch (shape) {
              case 'radio':
              case 'checkbox':
                if (shouldAttachRole(shape, elem)) {
                  elem.attr('role', shape);
                }
                if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
                  scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
                      getRadioReaction : getCheckboxReaction);
                }
                if (needsTabIndex) {
                  elem.attr('tabindex', 0);
                }
                break;
              case 'range':
                if (shouldAttachRole(shape, elem)) {
                  elem.attr('role', 'slider');
                }
                if ($aria.config('ariaValue')) {
                  var needsAriaValuemin = !elem.attr('aria-valuemin') &&
                      (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));
                  var needsAriaValuemax = !elem.attr('aria-valuemax') &&
                      (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));
                  var needsAriaValuenow = !elem.attr('aria-valuenow');
  
                  if (needsAriaValuemin) {
                    attr.$observe('min', function ngAriaValueMinReaction(newVal) {
                      elem.attr('aria-valuemin', newVal);
                    });
                  }
                  if (needsAriaValuemax) {
                    attr.$observe('max', function ngAriaValueMinReaction(newVal) {
                      elem.attr('aria-valuemax', newVal);
                    });
                  }
                  if (needsAriaValuenow) {
                    scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
                      elem.attr('aria-valuenow', newVal);
                    });
                  }
                }
                if (needsTabIndex) {
                  elem.attr('tabindex', 0);
                }
                break;
            }
  
            if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
              && shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
              // ngModel.$error.required is undefined on custom controls
              attr.$observe('required', function() {
                elem.attr('aria-required', !!attr['required']);
              });
            }
  
            if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
              scope.$watch(function ngAriaInvalidWatch() {
                return ngModel.$invalid;
              }, function ngAriaInvalidReaction(newVal) {
                elem.attr('aria-invalid', !!newVal);
              });
            }
          }
        };
      }
func_code_string: function(elem, attr) {
        if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
  
        var shape = getShape(attr, elem);
  
        return {
          post: function(scope, elem, attr, ngModel) {
            var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
  
            function ngAriaWatchModelValue() {
              return ngModel.$modelValue;
            }
  
            function getRadioReaction(newVal) {
              // Strict comparison would cause a BC
              // eslint-disable-next-line eqeqeq
              var boolVal = (attr.value == ngModel.$viewValue);
              elem.attr('aria-checked', boolVal);
            }
  
            function getCheckboxReaction() {
              elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
            }
  
            switch (shape) {
              case 'radio':
              case 'checkbox':
                if (shouldAttachRole(shape, elem)) {
                  elem.attr('role', shape);
                }
                if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
                  scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
                      getRadioReaction : getCheckboxReaction);
                }
                if (needsTabIndex) {
                  elem.attr('tabindex', 0);
                }
                break;
              case 'range':
                if (shouldAttachRole(shape, elem)) {
                  elem.attr('role', 'slider');
                }
                if ($aria.config('ariaValue')) {
                  var needsAriaValuemin = !elem.attr('aria-valuemin') &&
                      (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));
                  var needsAriaValuemax = !elem.attr('aria-valuemax') &&
                      (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));
                  var needsAriaValuenow = !elem.attr('aria-valuenow');
  
                  if (needsAriaValuemin) {
                    attr.$observe('min', function ngAriaValueMinReaction(newVal) {
                      elem.attr('aria-valuemin', newVal);
                    });
                  }
                  if (needsAriaValuemax) {
                    attr.$observe('max', function ngAriaValueMinReaction(newVal) {
                      elem.attr('aria-valuemax', newVal);
                    });
                  }
                  if (needsAriaValuenow) {
                    scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
                      elem.attr('aria-valuenow', newVal);
                    });
                  }
                }
                if (needsTabIndex) {
                  elem.attr('tabindex', 0);
                }
                break;
            }
  
            if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
              && shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
              // ngModel.$error.required is undefined on custom controls
              attr.$observe('required', function() {
                elem.attr('aria-required', !!attr['required']);
              });
            }
  
            if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
              scope.$watch(function ngAriaInvalidWatch() {
                return ngModel.$invalid;
              }, function ngAriaInvalidReaction(newVal) {
                elem.attr('aria-invalid', !!newVal);
              });
            }
          }
        };
      }
func_documentation_string: Make sure watches are fired after any other directives that affect the ngModel value