Angular:当输入类型="number" 但未输入数字时如何触发 ngChange

Angular: how to fire ngChange when input type="number" but not entered a number

我正在构建一个 angular 指令,其中我有两个数字输入,它们一起代表一个年龄范围。

我想要实现的是能够通过以下方式使用该指令:

<input-age-range
    name="ageRange"
    ng-model="filterUpdateVM.ageRange">
</input-age-range>
<span ng-if="myCtrlVM.form.ageRange.$error.ageRange">
    Please, enter a valid age range.
</span>

并且能够在输入的年龄范围不正确时显示自定义错误。

我的指令 html 模板看起来是这样的:

<div class="col-md-3">
    <input type="number"
           class="form-control"
           placeholder="Minimum age"
           name="ageMin"
           min="18"
           max="80"
           ng-change="checkAndValidateAgeRange()"
           ng-model="ageRange.ageMin"
           ng-model-options="{allowInvalid: true}">
</div>
<div class="col-md-3">
    <input type="number"
           class="form-control"
           placeholder="Maximum age"
           name="ageMax"
           min="18"
           max="80"
           ng-change="checkAndValidateAgeRange()"
           ng-model="ageRange.ageMax"
           ng-model-options="{allowInvalid: true}">
</div>

每次用户在输入中键入任何内容时,我都希望检查输入的范围是否正确:

到目前为止 ng-model-options="{allowInvalid: true}" 将在我的指令中触发 ngChange 函数,以防输入的任何年龄不在所需的年龄范围 (18-80) 之间 - 这样我可以进行一些检查并设置输入错误(如果有)并显示它。

我的问题是,如果最初输入的年龄不是数字,则不会调用 ngChange:它将无法进行错误检查,因此不会显示任何错误。在这种情况下,如何在不更改输入 type="number" 的情况下调用我的 ngChange 函数?

编辑:Jsfiddle 添加: http://jsfiddle.net/afkf96qh/

您不能在 type='number' 上使用 allowInvalid,因为给定 here。您可以设置 type='text',然后在 ng-change 处理程序中处理验证,如果您的意图是使用 type='number' 显示验证消息。

要在控制器中设置表单的有效性,请参考this link

结帐this fiddle

$scope.checkAndValidateAgeRange = function(name, model) {
    if (name === 'ageMin') {
        if (angular.isNumber(model)) {
            if (model < $scope.age.min) {
                $scope.minAgeMessage = 'You are under age';
            } else if (model > $scope.age.max) {
                $scope.minAgeMessage = 'You are too old';
            } else {
                $scope.minAgeMessage = '';
            }
        } else {
            $scope.minAgeMessage = 'Enter Only Numbers';
            $scope.ageRange.ageMin = null;
        }
    }

    if (name === 'ageMax') {
        if (angular.isNumber(model)) {
            if (model <= $scope.ageRange.ageMin) {
                $scope.maxAgeMessage = 'You are under age';
            } else if (model > $scope.age.max) {
                $scope.maxAgeMessage = 'You are too old';
            } else {
                $scope.maxAgeMessage = '';
            }
        } else {
            $scope.maxAgeMessage = 'Enter Only Numbers';
            $scope.ageRange.ageMax = null;
        }
    }
}

经过一天的努力弄清楚发生了什么,我终于实现了我正在寻找的行为。

首先,ng-model-options="{allowInvalid: true}" 与解决我的问题无关,所以我将其从我的输入中删除。我的指令 html 模板现在看起来是这样的:

<div class="col-md-3">
    <input type="number"
           class="form-control"
           placeholder="Minimum age"
           name="ageMin"
           min="18"
           max="80"
           ng-model="ageRange.ageMin"
           ng-change="checkAndValidateAgeRange()">
</div>
<div class="col-md-3">
    <input type="number"
           class="form-control"
           placeholder="Maximum age"
           name="ageMax"
           min="18"
           max="80"
           ng-model="ageRange.ageMax"
           ng-change="checkAndValidateAgeRange()">
</div>

导致未触发 ng-change="checkAndValidateAgeRange()" 的问题是我在 ngModel $render 函数中初始化 ageRange 变量的方式:

angular
    .module('myModule')
    .directive('myDirective', myDirective);

function myDirective() {

    var directive = {
        templateUrl: 'myTemplate.html',
        restrict: 'E',
        require:  ['^form', 'ngModel'],
        link: linkFunc
    };

    return directive;

    /////////

    function linkFunc(scope, element, attrs, ctrls) {
        scope.form = ctrls[0];
        scope.ageRange = {};
        scope.checkAndValidateAgeRange = checkAndValidateAgeRange;

        var ngModel = ctrls[1];
        ngModel.$render = getAgeRange;

        function checkAndValidateAgeRange() {
            // fired when the model changes
        };

        // $render function
        function getAgeRange() {
            scope.ageRange.ageMin = ngModel.$viewValue.ageMin;
            scope.ageRange.ageMax = ngModel.$viewValue.ageMax;
        };
    };

};

在某些情况下,传递给指令的 ngModel 对象的属性 - ageMinageMax - 都可以是 undefined

而且我们都知道当我们的输入带有 type="[whatever]"min="18"max="80" 等限制并且输入的数据不符合这些要求时会发生什么:它在模型中设置为 undefined

因此,如果上述属性最初传递给设置为 undefined 的指令,并且您在 <input type="number ...> 中输入了一个值,例如,该值不是数字...绑定模型的值仍为 undefined,因此模型中不会有任何更改使 ng-change 不会触发。

我最终解决这个问题的方法是将 ageRange.ageMinageRange.ageMax 初始化为 null 如果它们作为 undefined 传递,在我的 [=16] =]函数:

ngModel.$render = getAgeRange;

// $render function
function getAgeRange() {
    scope.ageRange.ageMin = ngModel.$viewValue.ageMin || null;
    scope.ageRange.ageMax = ngModel.$viewValue.ageMax || null;
};

这样,当输入无效输入时,模型的 属性 值将从 null 变为 undefined,导致 ng-change 触发。