Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS dynamic required attribute in directive and form validation

I have a directive that receives whether an element should be required or not from a REST api. Right now, I can't seem to get the form to invalidate when an attribute is set to required.

So, in essence I'm able to dynamically add the 'required' attribute from the directive below, but it doesn't invalidate the form. Looking through chrome I see that, even though the required attribute exists, a required entry in the $error array doesn't exist.

app.directive('requireiftrue', function ($compile) {
    return {
        require: '?ngModel',
        link: function (scope, el, attrs, ngModel) {
            if (!ngModel) {
                return;
            }

            if(attrs.requireiftrue==="true"){
                console.log('should require');
                el.attr('required', true);
                $compile(el.contents())(scope);
            }
            else{
                console.log('should not require');   
            }
        }
    };
});

Here's a jsfiddle to illustrate the problem. And, here's sample JSON returned from my rest API

{
    race: false,
    martialStatus: true,
}

EDIT: While the accepted answer got me up and running, I still had a good bit of finagling to do.

Namely: 1. Resolving a deferred promise to ensure that my form actually receives the required fields to validate 2. observing my 'requireiftrue' attribute

My solution

module config:

function config($stateProvider) {
    $stateProvider

    .state('testState', {
        url: '/test/form',
        controller: 'TestCtrl',
        templateUrl: 'test/form/testForm.tpl.html',
        resolve: {
            formDefaultService: function getFormDefaults($q, dataservice) {
                // Set up a promise to return
                var deferred = $q.defer();
                var myData = dataservice.getFormDefaults();
                deferred.resolve(myData);

                return deferred.promise;
                //return 
            }
        },

        data: {
            pageTitle: 'Test Info'
        }
    });
}

And, finally the directive / HTML that receives api data:

Directive:

.directive('requireiftrue', function ($compile) {
    return {
        require: '?ngModel',
        link: function (scope, el, attrs, ngModel) {
            if (!ngModel) {
                return;
            }
            attrs.$observe('requireiftrue', function(value){ 
                if(value==="true"){
                    el.attr('required', true);
                    el.removeAttr('requireiftrue');
                    $compile(el[0])(scope);
                }
            });
        }
    };
});

HTML:

<input max="40"
requireiftrue={{defaults.validation.name}}
validNumber
id="name"
name="name"
type="text"
ng-model="test.name"
class="form-control">
like image 490
olingern Avatar asked Dec 24 '22 23:12

olingern


1 Answers

You had two issues: The first is el.contents() returned an empty array. so The first thing you should do is change it to el[0]. But had el.contents() worked you would hav had a much more serious problem. You would have been trying to compile a directive that has itself as a directive which would lead to an infinite loop (well until the browser crashed any way). So here is the revised code:

var app = angular.module('form-example', []);

app.directive('requireiftrue', function ($compile) {
    return {
        require: '?ngModel',
        link: function (scope, el, attrs, ngModel) {
            if (!ngModel) {
                return;
            }

            if(attrs.requireiftrue==="true"){
                console.log('should require');
                el.attr('required', true);
                el.removeAttr('requireiftrue');
                $compile(el[0])(scope);
            }
            else{
                console.log('should not require');   
            }
        }
    };
});

I should note however that now this directive is a one-off. If the model will change, the directive will not be on the element any longer to deal with it.

like image 191
Aviv Shaked Avatar answered Dec 27 '22 13:12

Aviv Shaked