5

I would like to use the built in form validation provided by AngularJS. However, within the form I am using custom directives that each have an isolate scope. Because of this the form element does not have access to the bound values.

Any idea how to fix this?

or, is it possible to use AngularJS validation without the use of a form?

The ng-minlength and ng-required directives are not triggering the form validation.

<div ng-app="myApp" ng-controller="myCtrl">
    <form name="myForm" novalidate>
        <do-something ng-model="variable"></do-something>
        <h4 data-ng-if="myForm.myElement.$error.required">Please enter something</h4>
        <h4 data-ng-if="myForm.myElement.$error.greaterThanOne">Please enter a value greater than 1</h4>
        <h4 data-ng-if="myForm.myElement.$error.minLength">Please enter something longer than 1 digit</h4>
    {{myForm.myElement.$error}}     
    </form>
</div>

var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
});
app.directive('doSomething', function () {
    return {
        restrict: 'E',
        require: '?ngModel',
        scope: {
            model: '=ngModel'
        },
        template: 
            '<div>' +
            '  <input name="myElement" ng-model="model" ng-required ng-minlength="1" />' +
            '</div>'
    }
});

Full Plunk can be found here: Here is a plunkr that demonstrates the problem: http://plnkr.co/edit/iWyvX2?p=preview

2
  • Have you passed in the value as an attribute to your directive? You should be able to set the scope on that particular value as bidirectional I would have thought. I'm making assumptions here though; post a Fiddle. Commented Jun 23, 2014 at 6:52
  • I have posted a plunkr to illustrate the problem. I have passed the attribute into the directive. Can you see anything wrong? Commented Jun 23, 2014 at 13:10

3 Answers 3

2

From my understanding, yes you have to use a form for validation.

The way in which I validate is to set up a directive like below

module.directive('ngDoSomething', function() {
    restrict: 'A'
    require: '?ngModel',
    scope: {
        model: '=ngModel'
    }
    link: function($scope, element, attrs, ngModel) {
    $scope.$watch('model', function(val) {
        ngModel.$setValidity('required', !!val);
        ngModel.$setValidity('greaterThanOne', val > 1);
    }
});

Then use the html

<form name="somethingForm">
  <input name="somethingElement" data-ng-do-something data-ng-model="variable" />
  <h4 data-ng-if="somethingForm.somethingElement.$error.required">Please enter something</h4>
  <h4 data-ng-if="somethingForm.somethingElement.$error.greaterThanOne">Please enter a value greater than 1</h4>
</form>

I hope this helps

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

3 Comments

I have posted a plunkr (plnkr.co/edit/iWyvX2?p=preview) which more clearly illustrates the problem I'm having. I got your code to work, but cannot get mine to work. Any ideas?
@DanielMackay I've got a feeling in your example myForm.myElement won't be able to resolve (due to the isolate scopes). Is there a reason why you have to use a directive with a custom template rather than an input?
Yes, the reason is that some of the directives I'm using are more complex than a single input. Most of the input directives I'm using combine both a label and an input. Some are even more complex like a custom radio button that we have.
1

Ok Daniel, I was intrigued so I looked into it a bit further. The main difference between your code and @user3766487 is that you're using a directive element and injecting template. I believe this has caused a bit of ambiguity (you'll see that the directive itself and the inject input element both have the same name attribute). The linkage of the model doesn't appear to be quite working either.

I've changed your code to replace the template instead, which has made things a bit simpler. It appears to work:

http://plnkr.co/edit/eTSbjNe4KXW9IbUKtKuG

1 Comment

Thanks for your help @ChrisBell. I think we're slowly getting there. Is it possible to use standard angular validation directives (e.g. ng-maxlength)? Or do you always have to use $setValidity?
0

The ng-validators will work as expected with this 2 changes:

(1) Change the property name to "minlength" (instead of "minLength"):

<h4 data-ng-if="myForm.myElement.$error.minlength">

(2) Set ng-required to "true":

<input name="myElement" ... ng-required="true">

Setting minlength to "1" does not do anything because form validation does not check minlength wen the input is empty. If you set minlength to "5" and type one character in the input, you will see the message "Please enter something longer than 5 digit"

http://plnkr.co/edit/porkuq5JcKDU89s8g8ZT?p=preview

Your custom validator "greaterThanOne" is defined on the do-something directive. You can show its message by adding a name attribute such as myElementContainer:

<do-something name="myElementContainer" ng-model="myElement"></do-something>
  <h4 data-ng-show="myForm.myElementContainer.$error.greaterThanOne">Please enter a value greater than 1</h4>

I would recommend to to define the logic in another directive as an attribute to the input element.

Also, using $validators is recommended over calling $setValidity: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

Comments

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.