Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Form Validation with Dependent Fields in AngularJS

I have an object that has 2 fields, while 1 should be less than or equal to another.

Say it's HDD quota settings and I need the threshold to be less than or equal to HDD's size.

I am trying to use angular's ui-utils#validate.

This is how I got so far: http://embed.plnkr.co/EysaRdu2vuuyXAXJcJmE/preview (i hope the link will work)

The problem that I am having is that it works to one direction:

Setting size and then playing with threshold works ok

But if I try to change size, after threshold is in invalid state - nothing happens. This is because invalid threshold is not set on the model and size id being compared against null or undefined (or something like that).

On one hand I understand the logic of not setting invalid value on the model... but here it is getting in my way.

So, any help making this work will be appreciated.

like image 603
Michael Vashchinsky Avatar asked May 28 '13 17:05

Michael Vashchinsky


2 Answers

I have played with custom directives and cooked something that works for my case.

On my input for threshold I have less-than-or-equal="quota.size" directive, passing it the model's property to validate against (I want quota.threshold to be less than or equal to quota.size):

<input type="number" name="threshold" 
    ng-model="quota.threshold" 
    required 
    less-than-or-equal="quota.size" />

In link function of lessThanOrEqual directive it starts to watch the quota.size and when quota.size changes it just tries to set the current view value of threshold on model:

link: (scope, elem, attr, ctrl) ->
    scope.$watch attr.lessThanOrEqual, (newValue) ->
        ctrl.$setViewValue(ctrl.$viewValue)

Then there is the parser that does the validation by calling scope.thresholdValidate(thresholdValue) method passing it the candidate value. This method returns true if validation succeeded and if it does - it returns the new value, otherwise - current model's value:

    ctrl.$parsers.push (viewValue) ->
        newValue = ctrl.$modelValue
        if not scope.thresholdValidate viewValue    
            ctrl.$setValidity('lessThanOrEqual', false)
        else
            ctrl.$setValidity('lessThanOrEqual', true)
            newValue = viewValue
        newValue

I am pushing the parser to parser collection, as opposite to unshifting it like most of the examples suggest, because I want angular to validate required and number directives, so I get here only if I have a valid and parsed number (less work for me, but for text inputs I probably should do the parsing job)

Here is my playground: http://embed.plnkr.co/EysaRdu2vuuyXAXJcJmE/preview

like image 146
Michael Vashchinsky Avatar answered Nov 01 '22 23:11

Michael Vashchinsky


Better late than never, you need to add ng-model-options="{allowInvalid:true}" to your form input elements to stop this happening - the problem is that when a promise is rejected (e.g. using $q or $http) the model, by default, is not updated. Crazy huh! Cost me a day working this out.

I have written a plunkr specifically for this problem - Trust me this code is good ... http://embed.plnkr.co/xICScojgmcMkghMaYSsJ/preview

like image 26
danday74 Avatar answered Nov 02 '22 00:11

danday74