2

Edit: Massively simplified to get to the core of the problem

In Angular (v1.2.22) validation, if the value of max depends on another value, and that value updates, the validation state does not automatically update.

var app = angular.module('app',[]).
controller('TestCtrl', function($scope){
  $scope.partWidth = 10;
});

HTML:

<form name="itemForm">
  <label for="partWidth">Part width</label>
  <input id="partWidth" name="partWidth" min="10" max="180"  ng-model="partWidth" placeholder="mm" required type="number">

  <label for="cutterwidth">Cutter width</label>
  <input id="cutterwidth" name="cutterwidth" min="10" max="{{ partWidth }}"  ng-model="cutterwidth" placeholder="mm" required type="number">
</form>

Updated Plunker http://plnkr.co/edit/lNemYyFrHF9gyRgY8KIT

The ng-invalid class is not removed unless the cutterwidth itself is edited.

a) Is this a bug?

b) Is there a workaround? (e.g. force validation to run, somehow trigger the input event etc)

1
  • Interestingly, if you watch at the max="" attribute of cutterwidth in the rendered page it DOES update live as the value of partwidth is changed. However Angular only removes the ng-invalid class when the cutterwidth itself is edited, this is not triggered when the value of max changes. Is this a bug? Commented Aug 20, 2014 at 15:12

2 Answers 2

2

a) I think it's this bug.

b) My workaround, after much epic battling, was to avoid using the native max attribute entirely, and to build a custom directive instead.

I'm exposing the ngAppMax attribute to the scope, and passing in ngModel using the =. I don't fully understand this but it works.

I'm then comparing the two values and using $setValidity on the model (named 'ctrl').

Here's a working Plunker, or see below:

HTML

<form name="itemForm">
  <input name="partWidth" min="10" max="300" ng-model="partWidth" placeholder="mm" required type="number">
  <input name="cutterwidth" min="10" ng-app-max="{{ partWidth }}" ng-model="cutterWidth" placeholder="mm" required type="number">
</form>

JS

angular.module('app',[]).
controller('TestCtrl', function($scope){}).
directive('ngAppMax', function(){
  return {
    require: 'ngModel',
    scope: {
      ngAppMax: '@',
      ngModel: '='
    },
    link: function(scope, element, attrs, ctrl){

      scope.$watch('ngAppMax', function(newVal){
        validate(scope.ngModel, newVal, ctrl);
      });

      scope.$watch('ngModel', function(val){
        validate(val, scope.ngAppMax);
      });

      function validate(thisVal, maxVal){
        if(thisVal > maxVal){
          ctrl.$setValidity('range', false);
        } else {
          ctrl.$setValidity('range', true);
        }
      }

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

Comments

0

Actually, you have missed out a little detail in the logic.

For your PartWidth, what you need to do is to check whether the user has input anything below 10, or anything below the cutterwidth. Thus, a getMax function should do the trick.

    <input id="width" name="width" min="{{ getMax(10, cutterwidth) }}" max="180"   ng-model="width"    placeholder="mm" required type="number">

The getMax function is pretty straightforward. Just inverse the getMin function.

Here is the working plnkr

3 Comments

I could add that, but partWidth needs no dependency on the cutter width, and this doesn't actually solve the problem. Perhaps I didn't explain it well enough.
Okay, I re-read your question. Sorry for the wrong answer. If I am able to solve it I will update the answer.
I've completely rewritten it as a simplified scenario. Hopefully clearer now.

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.