0

I need to access input elements of a forms collection to do some custom validation. This worked just fine like this: scope.myForm.value3.$setValidity('complex', valid); until I converted value3 into a directive which in turn contains the input element named value3. Now I have no access to the underlying input element of the directive any more.

The important code goes as follows (working plunker here):

<form name="myForm" two-values>
      <input id="value1" name="value1" ng-model="f.v1"/>
      <input id="value2" name="value2" ng-model="f.v2"/>
      <szp-input id="value3" value="f.v3"></szp-input>
</form>

app.directive('twoValues', function ($parse) {
    function isValid(scope, value1, value2) {
        var valid = true;
        if (value1 == 0 && value2 == 0) {
            valid = false;
        } else if (value1 != 0 && value2 != 0) {
            valid = false;
        }
        console.log(scope.myForm);
        // note that I can access value1 and value2, but not value3
        // which is encapsulated in a directive
        scope.myForm.value1.$setValidity('complex', valid);
        scope.myForm.value2.$setValidity('complex', valid);
        // this throws and error saying that value3 is undefined 
        scope.myForm.value3.$setValidity('complex', false);
    }

    return {
        restrict: 'A',
        replace: true,
        link: function (scope, elem, attr, ctrl) {
            scope.$watch('f.v1', function () {
                isValid(scope, scope.f.v1, scope.f.v2);
            });
            scope.$watch('f.v2', function () {
                isValid(scope, scope.f.v1, scope.f.v2);
            });
        }
    };
});

1 Answer 1

1

It has something to do with how your szpInput directive is getting completely compiled/linked after the form directive has done it's work. What I noticed in your version of the code was that the form did have your custom value but it stored it as myForm.{{id}} which tells us that the form picked it up before AngularJs was able to transclude the value for {{id}} in the name attribute.

How I got it to work was by passing a function to the template attribute in the directive, instead of using templateUrl. In the template function I am building your template and setting the actual value for the name and id attributes.

app.directive('szpInput', function ($timeout) {

    return {
        restrict: 'E',
        replace: true,
        scope: {
            id: "@id",
            value: "=value"
        },
        template: function(elem,attrs) {
          var elemTpl = '<input type="text"'
            + ' ng-model="value"' 
            + ' id="' + attrs.id + '"'
            + ' name="' + attrs.id + '"'
            + ' class="form-control input-sm"/>';
          return elemTpl;
        }
    };
});

Here is an updated plunker

I have a feeling that something similar can be accomplished by using complile and/or the $complile service but I'm not too familiar with how to best use them.

Sign up to request clarification or add additional context in comments.

1 Comment

So, you basically say I should dump templateUrl and use template instead. It does seem to work, but man, it is ugly. Hate to use html code as a string. I would really like to have the html in a separate file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.