Angularjs ngModel.$setValidity只工作一次

Angularjs ngModel.$setValidity只工作一次,angularjs,twitter-bootstrap,validation,angularjs-directive,datepicker,Angularjs,Twitter Bootstrap,Validation,Angularjs Directive,Datepicker,我目前正在使用angular bootstrap ui datepicker弹出式验证,问题是我可以设置最大和最小日期并进行验证(仅当用户通过单击日历设置日期时),但当用户手动写入日期时,这些验证是无用的,我为此做了一个指令,但只验证和设置了一次错误,这是我的标记 <div class="form-group clearfix"> <div class="col-md-3 m-t-b-20"> <label>Date validation</

我目前正在使用angular bootstrap ui datepicker弹出式验证,问题是我可以设置最大和最小日期并进行验证(仅当用户通过单击日历设置日期时),但当用户手动写入日期时,这些验证是无用的,我为此做了一个指令,但只验证和设置了一次错误,这是我的标记

<div class="form-group clearfix">
  <div class="col-md-3 m-t-b-20">
    <label>Date validation</label>
    <p class="input-group col-md-12">

      <input id="validationDate"
             type="text"
             name="validationDate"
             class="form-control"
             uib-datepicker-popup="{{ Ctrl.format }}"
             data-ng-model="Ctrl.formObj.validationDate"
             is-open="Ctrl.validationDate.opened"
             datepicker-options="Ctrl.dateOptions"
             ng-required="true"
             close-text="Close"
             placeholder="Fecha de radicacion"
             ng-click="Ctrl.openDatePicker('validationDate')"
             required
             date-validate/>

      <span class="input-group-btn">
        <button type="button"
                class="btn btn-default"
                ng-click="Ctrl.openDatePicker('validationDate')"
                data-ng-disabled="Ctrl.blockFields">
          <i class="glyphicon glyphicon-calendar"></i>
        </button>
      </span>

    </p>

    <!-- THE ERROR TO SHOW -->
    <p data-ng-show="stepOne.validationDate.$error.validbound"
       class="text-red">
      the selected date exeeds the max and min date boundaries
    </p>
  </div>
})


我想知道为什么只在第一次进行验证,并且在指令在链接函数中不执行任何操作之后-使用自定义验证创建验证函数,您可以在ngModel上添加$watch。$viewValue

scope.$watch(function () {
             return ngModel.$viewValue;
         }, validate);

我认为“模糊”比“键控”更好。

这里有几点

首先,矩的
isBetween()
中给出的日期是独占的,而
datePicker
minDate
maxDate
中给出的日期是包含的日期。因此,您需要传递其他参数,以在范围内包括这些最小和最大日期:

cDate.isBetween(minDate, maxDate, null, '[]')
其次,如果您正在寻找有关日期是否在范围内的即时反馈,则需要将
$setValidity
包装在
范围内。$apply
函数

如果不查看Datepicker弹出窗口的javascript,我无法确切说明为什么需要这样做,但从实验中我可以看出,它只在弹出窗口关闭时应用
ng invalid validbound
属性(而
ng valid validbound
在validity设置为true时应用)。我假设这是一种提高性能的方法,因为你无论如何不能使用弹出窗口选择一个出界日期,你只能选择另一种方法——从无效日期到使用弹出窗口选择一个有效日期

我大致是这样做的:

var dateValidate = function() {
  return {
    require: 'ngModel',
    link: function(scope, elem, attr, ngModel) {
      elem.bind('keyup', function(value) {

        var atrvls = scope.$eval(attr.datepickerOptions),
          maxDate = moment(atrvls.maxDate, 'DD/MM/YYYY'),
          minDate = moment(atrvls.minDate, 'DD/MM/YYYY'),
          cDate = moment(elem.val(), 'DD/MM/YYYY', true);

        if (!cDate.isValid()) {
          scope.$apply(ngModel.$setValidity('validbound', null));
          return false;
        }

        if (!cDate.isBetween(minDate, maxDate, null, '[]')) {
          scope.$apply(ngModel.$setValidity('validbound', false));
        } else {
          scope.$apply(ngModel.$setValidity('validbound', true));
        }

      });
    }
  };
};

这里有一个提示:

好的,这是一个选项,但我仍然不明白为什么在第一次验证后验证会失败不,嗯。。。对但是我忘了提到angular 1.6.1,我在plnker上更改了它,当你手动键入日期时,它不起作用我不知道你的意思是什么?我已将plunk更新为1.6.1,对于我来说,键入日期
15/02/2017
显示为绿色(在范围内),键入
25/02/2017
显示为红色(超出范围)。我正在使用Firefox,虽然我不希望它也依赖于浏览器。如果我输入“12/12/2018”,输入会变为红色,如果我删除最后一个字符,输入会变为正常,这是我正在搜索的预期行为,但是如果在这之后我再次输入“12/12/2016”(在范围内),输入会变为红色“12/12/2016”不在范围内,这就是它变红的原因。我设置的范围是2017年2月4日至2017年2月22日,否则,如果您希望边框在范围内保持正常颜色,并且仅在不在范围内时显示红色,则删除Plunk中的
#validationDate.ng validbound
绿色边框CSS规则
var dateValidate = function() {
  return {
    require: 'ngModel',
    link: function(scope, elem, attr, ngModel) {
      elem.bind('keyup', function(value) {

        var atrvls = scope.$eval(attr.datepickerOptions),
          maxDate = moment(atrvls.maxDate, 'DD/MM/YYYY'),
          minDate = moment(atrvls.minDate, 'DD/MM/YYYY'),
          cDate = moment(elem.val(), 'DD/MM/YYYY', true);

        if (!cDate.isValid()) {
          scope.$apply(ngModel.$setValidity('validbound', null));
          return false;
        }

        if (!cDate.isBetween(minDate, maxDate, null, '[]')) {
          scope.$apply(ngModel.$setValidity('validbound', false));
        } else {
          scope.$apply(ngModel.$setValidity('validbound', true));
        }

      });
    }
  };
};