min/max validations not working if values are changed later

前端 未结 2 1726
清酒与你
清酒与你 2020-12-09 21:40

i have requirement where min value of one field depends on the input given in another field.



        
相关标签:
2条回答
  • 2020-12-09 21:50

    use ng-min/ng-max directives

    app.directive('ngMin', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, elem, attr, ctrl) {
                scope.$watch(attr.ngMin, function(){
                    if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
                });
    
                var isEmpty = function (value) {
                   return angular.isUndefined(value) || value === "" || value === null;
                }
    
                var minValidator = function(value) {
                  var min = scope.$eval(attr.ngMin) || 0;
                  if (!isEmpty(value) && value < min) {
                    ctrl.$setValidity('ngMin', false);
                    return undefined;
                  } else {
                    ctrl.$setValidity('ngMin', true);
                    return value;
                  }
                };
    
                ctrl.$parsers.push(minValidator);
                ctrl.$formatters.push(minValidator);
            }
        };
    });
    
    app.directive('ngMax', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, elem, attr, ctrl) {
                scope.$watch(attr.ngMax, function(){
                    if (ctrl.$isDirty) ctrl.$setViewValue(ctrl.$viewValue);
                });
                var maxValidator = function(value) {
                  var max = scope.$eval(attr.ngMax) || Infinity;
                  if (!isEmpty(value) && value > max) {
                    ctrl.$setValidity('ngMax', false);
                    return undefined;
                  } else {
                    ctrl.$setValidity('ngMax', true);
                    return value;
                  }
                };
    
                ctrl.$parsers.push(maxValidator);
                ctrl.$formatters.push(maxValidator);
            }
        };
    });
    
    0 讨论(0)
  • 2020-12-09 21:55

    I've developed a couple of directives that actually restrict the user from setting an invalid value instead of simply throwing an error when an invalid value is provided.

    These directives also do not require ngModel (though I doubt you would use them without) and what's really cool is that it will wrap the value around to the min/max if both settings are provided!

    I've tried to simplify the directives as much as possible to make them easier for our readers.

    Here is a JSFiddle of the whole thing: JSFiddle

    And here are the directives:

    app.directive('ngMin', function($parse){
        return {
            restrict: 'A',
            link: function(scope, element, attrs){
                function validate(){
                    if(element
                    && element[0]
                    && element[0].localName === 'input'
                    && isNumber(attrs.ngMin)
                    && isNumber(element[0].value)
                    && parseFloat(element[0].value) < parseFloat(attrs.ngMin)){
                        if(isNumber(attrs.ngMax)){
                            element[0].value = parseFloat(attrs.ngMax);
                            if(attrs.hasOwnProperty("ngModel"))
                                $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
                        }
                        else {
                            element[0].value = parseFloat(attrs.ngMin);
                            if(attrs.hasOwnProperty("ngModel"))
                                $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
                        }
                    }
                }
                scope.$watch(function(){
                    return attrs.ngMin + "-" + element[0].value;
                }, function(newVal, oldVal){
                    if(newVal != oldVal)
                        validate();
                });
                validate();
            }
        };
    });
    app.directive('ngMax', function($parse){
        return {
            restrict: 'A',
            link: function(scope, element, attrs){
                function validate(){
                    if(element
                    && element[0]
                    && element[0].localName === 'input'
                    && isNumber(attrs.ngMax)
                    && isNumber(element[0].value)
                    && parseFloat(element[0].value) > parseFloat(attrs.ngMax)){
                        if(isNumber(attrs.ngMin)){
                            element[0].value = parseFloat(attrs.ngMin);
                            if(attrs.hasOwnProperty("ngModel"))
                                $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMin));
                        }
                        else {
                            element[0].value = parseFloat(attrs.ngMax);
                            if(attrs.hasOwnProperty("ngModel"))
                                $parse(attrs.ngModel).assign(scope, parseFloat(attrs.ngMax));
                        }
                    }
                }
                scope.$watch(function(){
                    return attrs.ngMax + "-" + element[0].value;
                }, function(newVal, oldVal){
                    if(newVal != oldVal)
                        validate();
                });
                validate();
            }
        };
    });
    

    ...also, you will need this little helper function as well:

    function isNumber(n){
        return !isNaN(parseFloat(n)) && isFinite(n);
    }
    

    To invoke these directives, just set them on an input box where type="number":

    <input ng-model="myModel" ng-min="0" ng-max="1024" />
    

    And that should do it!

    When you provide both an ngMin and ngMax, these directive will wrap the value around, so that when your value becomes less than ngMin, it will be set to ngMax, and vice-versa.

    If you only provide ngMin or ngMax, the input value will simply be capped at these values.

    I prefer this method of preventing bad values rather than alerting the user that they have entered a bad value.

    0 讨论(0)
提交回复
热议问题