2

Taking a look to ngRequired directive I found that they not use isolated scope, but they manage to observe the "required" attribute and check if there are changes (getting the final boolean expression result)

attr.$observe('required', function() {
  validator(ctrl.$viewValue);
});

If in the controller scope I have a boolean var called isRequired I can directly write:

<input id="year"
          type="text"
          name="year"
          data-ng-model="currentVehicleEdit.year"
          data-ng-required="isRequired" />

and I get the expression evaluated to true or false.

I have tried the same approach on a directive (dropdown validation) but all I get is the text value for that attribute. So I have to enter something like this to get results ("true", "false"):

<select id="involvementType"
      name="involvementType"
      data-ng-model="currentVehicleEdit.involvementType"
      data-ng-options="a.name for a in involvementTypes"
      data-combocontainsinvalidselection="{{showForm}}"
>
</select>

If I try to use it in the same ways as in the ngRequired (data-combocontainsinvalidselection="showForm") I just got plain text ("showForm"), not the expression evaluated.

About the directive's code I have created:

mydirectives.directive('combocontainsinvalidselection', [
    function () {
        return {
            require: "?ngModel",
            link: function(scope, elm, attr, ctrl) {
                if (!ctrl) return;

                var validator = function (value) {
                    if (attr.combocontainsinvalidselection == true && value.id==0) {
                        ctrl.$setValidity('combocontainsinvalidselection', false);
                        return;
                    } else {
                        ctrl.$setValidity('combocontainsinvalidselection', true);
                        return value;
                    }
                };

                ctrl.$formatters.push(validator);
                ctrl.$parsers.unshift(validator);

                attr.$observe('combocontainsinvalidselection', function () {
                    validator(ctrl.$viewValue);
                });                               
            }
        };
    }
]);

How does the ng-required directive manage to get the expression evaluated?

user353gre3
  • 2,636
  • 4
  • 22
  • 26
Braulio
  • 1,668
  • 14
  • 20

4 Answers4

2

You can parse the attribute. Firstly, avoid {{}} around the showForm in your markup, and then use $parse in your condition like this:

 if (  $parse(attr.combocontainsinvalidselection)(scope) == true && value.id==0) {
     //some code

Do not forget to inject $parse into your directive declaration.

joe_coolish
  • 6,953
  • 13
  • 59
  • 108
Engineer
  • 43,887
  • 11
  • 83
  • 90
0

Just double checked, the parse is fine to get the value, but don't know how to observe the expressions (seems that only works with {{}}), and I would like to avoid isolated scope.

Tried this:

 attr.$observe($parse('combocontainsinvalidselection')(scope), function () {
      validator(ctrl.$viewValue);
 });
Braulio
  • 1,668
  • 14
  • 20
0

Had the same problem and just found the solution in another question: Angularjs: how to pass scope variables to a directive?

I can verify that it worked for me.

Edit: sorry, to be clear, this answer specifically, where the directive is used as "create-control='yourConditionalExpression'" in the HTML. If needed, you can use scope.$watch as well.

app.directive('createControl', function() {
  return {
    scope: {
      createControl:'='
    },
    link: function(scope, element, attrs){    
       element.text(scope.createControl);    
    }      
  }
}) 

EDIT: To address OP's specifications: this is the custom clone of ng-required that I implemented, and it successfully takes a condition and gets along with all other directives applied to the dropdown. You should be able to modify it to do whatever you need.

// Copy of ng-required that does not set the model value to 'undefined' when the user sets the dropdown to '' (not a valid final value for the model, but preferable to 'undefined' while the form is being filled out, since 'undefined' gives an ugly blank dropdown)

yourApp.directive('requiredSelect', function () {
  return {
    scope: {
        requiredSelect: '='
    },
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
        if (!ctrl) return;

        var validator = function (value) {
            if (scope.requiredSelect && ctrl.$isEmpty(value)) {
                ctrl.$setValidity('requiredSelect', false);
                return value; // like the original ng-required and other common validators, you might return undefined here if that's your preference
            } else {
                ctrl.$setValidity('requiredSelect', true);
                return value;
            }
        };

        ctrl.$formatters.push(validator);
        ctrl.$parsers.unshift(validator);

        scope.$watch('requiredSelect', function () {
            validator(ctrl.$viewValue);
        });
    }
  };
}); 
Community
  • 1
  • 1
  • My goal is to avoid using isolated scope (e.g. you have to do some strange workarounds to get two directive with isolated scope working applied to the same element). $observer plus {{}} works, but I don't know how they make it work for conditional expression in ngRequired. – Braulio May 15 '14 at 16:50
  • More code added to my answer -- I'm not sure whether it's what you're looking for, but it gets along with other directives as far as I've seen. My version is very related to ng-required, but you could branch out from there if desired. – Jennifer Gilbert May 16 '14 at 17:00
  • (I realize this still uses a scope. I just couldn't find any other way to accomplish the same thing, even with an identical copy of ng-required.) – Jennifer Gilbert May 16 '14 at 17:08
0

I'm not really sure how they're doing it so that you don't have to wrap your expression in {{...}}, but I did come up a workaround for one of my custom validators.

Here's what they do:

  attr.$observe('required', function(value) {
    // Do stuff
  });

Here's the workaround:

  scope.$watch(attr.myCustomValidator, function(value) {
    // Do stuff
  });
djdmbrwsk
  • 572
  • 5
  • 10