繁体   English   中英

自定义DatePicker Angular Formly字段不显示验证错误消息

[英]Validation error message doesn't appear for custom DatePicker Angular Formly field

我正在尝试使用Angular Datetime Picker作为Angular Formly输入类型。 我已经使它工作,我可以编辑和设置一个正确添加到绑定模型的值。

但是,我无法在常规输入字段中显示验证错误消息。

JS Bin和我到目前为止所得到的 正如您所看到的,当您退出该字段时,只有在您尝试提交时才会显示红色。 并且错误消息永远不会显示出来。

形式配置

formlyConfigProvider.setType({
  name: 'datepicker',
  templateUrl: "custom-template.html",
  overwriteOk: true,
  wrapper: ['bootstrapHasError'],
  defaultOptions: function defaultOptions(options) {
    return {
      templateOptions: {
        validation: {
          show: true
        }
      }
    };
  }
});

formlyConfigProvider.setWrapper({
  name: 'validation',
  types: ['input', 'datepicker'],
  templateUrl: 'error-messages.html'
});

字段

vm.fields = [
  {
    key: 'text',
    type: 'input',
    templateOptions: {
      label: 'Text',
      placeholder: 'Write something',
      required: true
    },
  },
  {
    key: 'date',
    type: 'datepicker',
    templateOptions: {
      label: 'Date',
      placeholder: 'Pick a date',
      required: true
    },
  }
];

模板

<script type="text/ng-template" id="custom-template.html">
  <div class="form-group">

      <label class="control-label" for="{{::id}}">{{to.label}} {{to.required ? '*' : ''}}</label>
      <div class="dropdown">
          <a class="dropdown-toggle" id="dropdown-{{options.key}}" role="button" data-toggle="dropdown">
          <div class="input-group">
              <input id="{{::id}}" name="{{::id}}" type="text" data-date-time-input="YYYY-MM-DD" class="form-control" data-ng-model="model[options.key]"><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
          </div>
        </a>
        <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
          <datetimepicker
              data-ng-model="model[options.key]"
              data-datetimepicker-config="{ dropdownSelector: '#dropdown-' + options.key, minView: 'day', startView: 'year', modelType: 'YYYY-MM-DDTHH:mm:ssZ'}"/>
        </ul>
      </div>
  </div>

</script>

<script type="text/ng-template" id="error-messages.html">
  <formly-transclude></formly-transclude>
  <div ng-messages="fc.$error" ng-if="form.$submitted || options.formControl.$touched" class="error-messages">
    <div ng-message="{{ ::name }}" ng-repeat="(name, message) in ::options.validation.messages" class="message">{{ message(fc.$viewValue, fc.$modelValue, this)}}</div>
  </div>
</script>

在深入研究之后,我可以看到你使用Angular Datetime Picker的控件与Angular Formly不完全兼容。

这是因为,它的覆盖AngularJS的原因ngModelController.$render()方法,因此没有设定值$touched像其他输入控件。

在代码的另一个原因是,在配置和模板error-messages.html被治疗定制控制与单个元件fc.$touchedfc.$errorfc.$viewValueDatePicker被渲染为元件组(阵列)。

要摆脱所有这些问题,您可以使用自定义指令设置$touched ,如下所示,

app.directive('setTouched', function MainCtrl() {
    return {
      restrict: 'A', // only activate on element attribute
      require: '?ngModel', // get a hold of NgModelController
      link: function(scope, element, attrs, ngModel) {
         if (!ngModel) return; // do nothing if no ng-model
         element.on('blur', function() {
            var modelControllers = scope.$eval(attrs.setTouched);
            if(angular.isArray(modelControllers)) {
              angular.forEach(modelControllers, function(modelCntrl) {
                modelCntrl.$setTouched();
              });
            }            
         });
      }
    };
  });

custom-template.html

<div class="input-group">
   <input set-touched="options.formControl" id="{{::id}}" name="{{::id}}" type="text" data-date-time-input="YYYY-MM-DD" class="form-control" data-ng-model="model['date1']"><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
</div>

并在下面的配置中添加fc[0].$touched以处理字段数组,

app.run(function run(formlyConfig, formlyValidationMessages) {
    formlyConfig.extras.errorExistsAndShouldBeVisibleExpression = 'form.$submitted || fc.$touched || fc[0].$touched';
    formlyValidationMessages.addStringMessage('required', 'This field is required');
});

并在error-messages.html添加以下部分来处理字段数组,

<div ng-messages="fc[0].$error" ng-if="form.$submitted || options.formControl[0].$touched" class="error-messages">
    <div ng-message="{{ ::name }}" ng-repeat="(name, message) in ::options.validation.messages" class="message">{{ message(fc[0].$viewValue, fc[0].$modelValue, this)}}</div>
</div>

此更改将解决此问题。

正如您可以看到一些设计问题,错误消息进一步向下显示,

您可以通过删除div包装器<div class="form-group">来更改custom-template.html ,如下所示,

<script type="text/ng-template" id="custom-template.html">
    <label class="control-label" for="{{::id}}"
           uib-popover="{{options.templateOptions.desc}}"
           popover-trigger="mouseenter"
           popover-placement="top-left"
           popover-popup-delay="500"
           popover-append-to-body="true">{{to.label}} {{to.required ? '*' : ''}}</label>

          <div class="dropdown">
              <a class="dropdown-toggle" id="dropdown-{{options.key}}" role="button" data-toggle="dropdown">
              <div class="input-group">
                  <input set-touched="options.formControl" id="{{::id}}" name="{{::id}}" type="text" data-date-time-input="YYYY-MM-DD" class="form-control" data-ng-model="model['date1']"><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
              </div>
            </a>
            <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
              <datetimepicker
                  data-ng-model="model[options.key]"
                  data-datetimepicker-config="{ dropdownSelector: '#dropdown-' + options.key, minView: 'day', startView: 'year', modelType: 'YYYY-MM-DDTHH:mm:ssZ'}"/>
            </ul>
          </div>

    </script>

我已经使用这些更改更新了您的JSBin

片段

 /* global angular */ (function() { 'use strict'; var app = angular.module('formlyExample', ['formly', 'formlyBootstrap', 'ngAnimate', 'ngMessages', 'ui.bootstrap.datetimepicker', 'ui.dateTimeInput'], function config(formlyConfigProvider) { formlyConfigProvider.setType({ name: 'datepicker', templateUrl: "custom-template.html", overwriteOk: true, wrapper: ['bootstrapHasError'], defaultOptions: function defaultOptions(options) { return { templateOptions: { validation: { show: true } } }; } }); formlyConfigProvider.setWrapper({ name: 'validation', types: ['input', 'datepicker'], templateUrl: 'error-messages.html' }); }); app.run(function run(formlyConfig, formlyValidationMessages) { formlyConfig.extras.errorExistsAndShouldBeVisibleExpression = 'form.$submitted || fc.$touched || fc[0].$touched'; formlyValidationMessages.addStringMessage('required', 'This field is required'); }); app.directive('setTouched', function MainCtrl() { return { restrict: 'A', // only activate on element attribute require: '?ngModel', // get a hold of NgModelController link: function(scope, element, attrs, ngModel) { if (!ngModel) return; // do nothing if no ng-model element.on('blur', function() { var modelControllers = scope.$eval(attrs.setTouched); if(angular.isArray(modelControllers)) { angular.forEach(modelControllers, function(modelCntrl) { modelCntrl.$setTouched(); }); } }); } }; }); app.controller('MainCtrl', function MainCtrl(formlyVersion) { var vm = this; vm.onSubmit = onSubmit; vm.model = {}; vm.options = {}; vm.env = { angularVersion: angular.version.full, formlyVersion: formlyVersion }; vm.fields = [ { key: 'text', type: 'input', templateOptions: { label: 'Text', placeholder: 'Write something', required: true }, }, { key: 'moretext', type: 'input', templateOptions: { label: 'More Text', placeholder: 'Write something else', }, }, { key: 'date', type: 'datepicker', templateOptions: { label: 'Date', placeholder: 'Pick a date', required: true }, } ]; vm.originalFields = angular.copy(vm.fields); // function definition function onSubmit() { if (vm.form.$valid) { vm.options.updateInitialValue(); alert(JSON.stringify(vm.model), null, 2); } } }); })(); 
 body { margin: 20px } .formly-field { margin-bottom: 30px; } .error-messages { position: relative; } .error-messages, .message { opacity: 1; transition: .3s linear all; } .message { font-size: .8em; position: absolute; width: 100%; color: #a94442; margin-top: 4px; } .error-messages.ng-enter.ng-enter-active, .message.ng-enter.ng-enter-active { opacity: 1; top: 0; } .error-messages.ng-enter, .message.ng-enter { opacity: 0; top: -10px; } .error-messages.ng-leave, .message.ng-leave { opacity: 1; top: 0; } .error-messages.ng-leave-active, .message.ng-leave-active { opacity: 0; top: -10px; } 
 <!DOCTYPE html> <html> <head> <!-- jQuery --> <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!-- Twitter bootstrap --> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- apiCheck is used by formly to validate its api --> <script src="//npmcdn.com/api-check@latest/dist/api-check.js"></script> <!-- This is the latest version of angular (at the time this template was created) --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script> <!-- This is the latest version of formly core. --> <script src="//npmcdn.com/angular-formly@latest/dist/formly.js"></script> <!-- This is the latest version of formly bootstrap templates --> <script src="//npmcdn.com/angular-formly-templates-bootstrap@latest/dist/angular-formly-templates-bootstrap.js"></script> <script src="https://rawgit.com/angular/bower-angular-messages/v1.4.4/angular-messages.js"></script> <script src="https://rawgit.com/angular/bower-angular-animate/v1.4.4/angular-animate.js"></script> <!-- Moment --> <script src="https://cdn.rawgit.com/moment/moment/develop/min/moment-with-locales.min.js"></script> <!-- Datetime picker --> <script type="text/javascript" src="https://cdn.rawgit.com/dalelotts/angular-bootstrap-datetimepicker/master/src/js/datetimepicker.js"></script> <script type="text/javascript" src="https://cdn.rawgit.com/dalelotts/angular-bootstrap-datetimepicker/master/src/js/datetimepicker.templates.js"></script> <link href="https://cdn.rawgit.com/dalelotts/angular-bootstrap-datetimepicker/master/src/css/datetimepicker.css" rel="stylesheet"> <script type="text/javascript" src="https://cdn.rawgit.com/dalelotts/angular-date-time-input/master/src/dateTimeInput.js"></script> <title>Angular Formly Example</title> </head> <body ng-app="formlyExample" ng-controller="MainCtrl as vm"> <div> <form ng-submit="vm.onSubmit()" name="vm.form" novalidate> <formly-form model="vm.model" fields="vm.fields" options="vm.options" form="vm.form"> <button type="submit" class="btn btn-primary submit-button">Submit</button> <button type="button" class="btn btn-default" ng-click="vm.options.resetModel()">Reset</button> </formly-form> </form> <hr /> <h2>Model</h2> <pre>{{vm.model | json}}</pre> <h2>Fields <small>(note, functions are not shown)</small></h2> <pre>{{vm.originalFields | json}}</pre> <h2>Form</h2> <pre>{{vm.form | json}}</pre> </div> <!-- Put custom templates here --> <script type="text/ng-template" id="custom-template.html"> <label class="control-label" for="{{::id}}" uib-popover="{{options.templateOptions.desc}}" popover-trigger="mouseenter" popover-placement="top-left" popover-popup-delay="500" popover-append-to-body="true">{{to.label}} {{to.required ? '*' : ''}}</label> <div class="dropdown"> <a class="dropdown-toggle" id="dropdown-{{options.key}}" role="button" data-toggle="dropdown"> <div class="input-group"> <input set-touched="options.formControl" id="{{::id}}" name="{{::id}}" type="text" data-date-time-input="YYYY-MM-DD" class="form-control" data-ng-model="model['date1']"><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span> </div> </a> <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"> <datetimepicker data-ng-model="model[options.key]" data-datetimepicker-config="{ dropdownSelector: '#dropdown-' + options.key, minView: 'day', startView: 'year', modelType: 'YYYY-MM-DDTHH:mm:ssZ'}"/> </ul> </div> </script> <script type="text/ng-template" id="error-messages.html"> <formly-transclude></formly-transclude> <div ng-messages="fc.$error" ng-if="form.$submitted || options.formControl.$touched" class="error-messages"> <div ng-message="{{ ::name }}" ng-repeat="(name, message) in ::options.validation.messages" class="message">{{ message(fc.$viewValue, fc.$modelValue, this)}}</div> </div> <div ng-messages="fc[0].$error" ng-if="form.$submitted || options.formControl[0].$touched" class="error-messages"> <div ng-message="{{ ::name }}" ng-repeat="(name, message) in ::options.validation.messages" class="message">{{ message(fc[0].$viewValue, fc[0].$modelValue, this)}}</div> </div> </script> </body> </html> 

您应该在formlyConfigProvider return validation ,而不将其作为templateOptions的值传递。 返回

validation: {
    show: true
}

代替

templateOptions: {
    validation: {
        show: true
    }
}

你的formlyConfigProvider应该是这样的:

formlyConfigProvider.setType({
    name: 'datepicker',
    templateUrl: "custom-template.html",
    overwriteOk: true,
    wrapper: ['bootstrapHasError'],
    defaultOptions: function defaultOptions(options) {
        return {
                 validation: {
                    show: true
               }    
        };
    }
});

是工作代码的JSBin。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM