1

In the code below I am compiling a directive that includes an expression for ng-required. As long as the expression is true or false, all is well, however when ng-required="appConfig.requireBirthdate", the eval is failing. So, I must be doing something wrong. How do I get the true false value for the ng-required expression while in the context of compiling a directive?

The last line of the code is where I'm having trouble, and that problem is with the eval() eval is not happening in the context of the scope where that expression would be defined.

    return {
        restrict: 'E',
        priority: 102,     // We need this directive to happen before ng-model and the boolean directives
        terminal: true,   // We are going to deal with this element
        compile: function(element, attrs) {
            if ( attrs.ngRepeat || attrs.ngSwitch || attrs.uiIf ) {
                throw new Error('The ng-repeat, ng-switch and ui-if directives are not supported on the same element as the field directive.');
            }
            if ( !attrs.ngModel ) {
                throw new Error('The ng-model directive must appear on the field element');
            }

            // Extract the label and validation message info from the directive's original element
            var validationMessages = getValidationMessageMap(element);
            var labelContent = getLabelContent(element, eval(attrs['ngRequired']));
boatcoder
  • 17,525
  • 18
  • 114
  • 178

1 Answers1

0

Angular expressions are evaluated against a scope with $eval:

$scope.$eval('a+b');

you can check the docs here: https://docs.angularjs.org/api/ng/type/$rootScope.Scope

However, in your example I only see a compile function, and at compile time, the directive's scope isn't available. Scopes are linked to the directive and you can use them with the link callback in your directive definition:

{
  priority: 102,
  terminal: true, 
  link: function( $scope, $el, $attrs ) {
    alert($scope.$eval('appConfig.requireBirthdate') )
  }
}

Alternatively, you can use isolate scope bindings to use dynamic attributes:

{
  priority: 102,
  terminal: true
  scope: {
    required: '&ngRequired'
  },
  link: function( scope, $el, $attrs ) {
      alert( $attrs.required() );
  } 
}

the docs for directive binding can be found in the official directive guide: https://docs.angularjs.org/guide/directive .


EDIT: I think I misread your question, but the answer is still: the scope doesn't make sense at compile time. A directive is compiled once but can be linked several times. The first answer here give you the details: AngularJS : link vs compile vs controller

But you may get the parent scope in a hacky way:

compile: function( element, attrs ) {
   scope = angular.element(element).scope();
}
Community
  • 1
  • 1
BiAiB
  • 12,932
  • 10
  • 43
  • 63
  • I think you might be right! unfortunately the hack at the bottom does not work, and even if it did, there is a small window that it still would not behave as desired. – boatcoder Dec 09 '14 at 13:30