jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析


Posted in Javascript onOctober 30, 2016

类似的文章已有,请看这里,个人感觉稍显复杂,日前也打算写一个简单的给项目用,一些关键点记录于此。最终效果如下:

jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析

后端使用Asp.net mvc5,前端框架有:jquery.validate、jquery.validate.unobtrusive、requirejs、Bootstrap,都是当前最/较新版本。jquery.validate就不用说了,目前比较流行的前端校验组件;jquery.validate.unobtrusive基于jquery.validate,是为了配合Asp.net mvc,微软自己写的,NuGet下可查找Microsoft.jQuery.Unobtrusive.Validation安装,具体怎么用请继续往下看。

首先在后台我们定义实体类:

/// <summary>
/// 厂家信息
/// </summary>
public class Manufacturer : OperatedModel
{
  [Key]
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int ID { get; set; }
  /// <summary>
  /// 信用代码/注册号
  /// </summary>
  [Required(ErrorMessage = "信用代码/注册号不能为空")]
  [MaxLength(30)]
  public string EnterpriseNo { get; set; }
  /// <summary>
  /// 企业名称
  /// </summary>
  [Required(ErrorMessage = "企业名称不能为空")]
  public string EnterpriseName { get; set; }
  /// <summary>
  /// 注册地址
  /// </summary>
  [Required(ErrorMessage = "注册地址不能为空")]
  public string RegisteredAddress { get; set; }
  /// <summary>
  /// 法人
  /// </summary>
  [Required(ErrorMessage = "法人不能为空")]
  public string ArtificialPerson { get; set; }
  /// <summary>
  /// person in charge 负责人
  /// </summary>
  [Required(ErrorMessage = "负责人不能为空")]
  public string PIC { get; set; }
  [Required(ErrorMessage = "手机号不能为空")]
  [RegularExpression(RegexLib.Mobile, ErrorMessage = "手机号码格式不正确")]
  public string Mobile { get; set; }
    
  [EmailAddress]
  public string Email { get; set; }
  /// <summary>
  /// 商铺号
  /// </summary>
  public string ShopNumber { get; set; }
  /// <summary>
  /// 店铺管理员姓名
  /// </summary>
  public string StoreManagerName { get; set; }
  /// <summary>
  /// 店铺管理员联系方式
  /// </summary>
  [RegularExpression(RegexLib.Mobile, ErrorMessage="手机号码格式不正确")]
  public string StoreManagerNumber { get; set; }
  /// <summary>
  /// 主要执照, 三证合一营业执照
  /// </summary>
  public string MainLicence { get; set; }
  /// <summary>
  /// json, 其他执照,如生产许可证
  /// </summary>
  public string OtherLicence { get; set; }
  /// <summary>
  /// 入驻日期
  /// </summary>
  [Required(ErrorMessage = "入驻日期不能为空")]
  public DateTime EnterDate { get; set; }
  /// <summary>
  /// 离场日期
  /// </summary>
  [Required(ErrorMessage = "截止日期不能为空")]
  public DateTime QuitDate { get; set; }
  /// <summary>
  /// 厂家可提现余额
  /// </summary>
  public decimal Balance { get; set; }
}

实体各属性上面有Attribute形式的校验规则,当用户提交一个Model到后端Action时,MVC框架会据此自动帮我们完成校验工作,于是后端开发就很开心。然而在数据提交之前,前端也有必要进行第一轮的校验,如果使用jquery.validate,那么需要在js或标签里再写一遍类似的规则,能不能复用后端已有的代码呢?我们以属性EnterpriseNo为例,在cshtml中写:

@Html.TextBoxFor(m => m.BasicInfo.EnterpriseNo, new { placeholder = "必填项", @class = "form-control" })

最终生成的html如下:

<input class="form-control" data-val="true" data-val-maxlength="字段 EnterpriseNo 必须是最大长度为“30”的字符串或数组类型。" data-val-maxlength-max="30" data-val-required="信用代码/注册号不能为空" id="BasicInfo_EnterpriseNo" name="BasicInfo.EnterpriseNo" placeholder="必填项" value="" data-original-title="" title="" type="text">

标签里面自动加上了很多data-开头的属性,data-val表示该控件需要校验,其它data-开头的就是一系列校验规则和失败时的错误信息,错误信息可以自定义,否则框架会给你生成类如“字段 EnterpriseNo 必须是最大长度为30的字符串或数组类型。”这种机器翻译语言。当然这些属性jquery.validate是不认的,要让jquery.validate认识,就需要jquery.validate.unobtrusive出马了。

现在我们来说这些js如何配合使用。

新版本的jquery.validate已经支持AMD模式,所以可以直接使用requirejs加载,jquery.validate.unobtrusive则不行,需要shim配置,代码:

require.config({
      baseUrl: '/scripts',
      paths: {
        "jquery": 'jquery-2.2.3.min',
        "knockout":'knockout-3.4.0',
        "bootstrap":'../components/bootstrap/3.3.6/js/bootstrap.min','validate':'jquery.validate',
        'validateunobtrusive':'jquery.validate.unobtrusive.min'
      },
      shim : {
        'bootstrap' : {
          deps : [ 'jquery' ],
          exports : 'bootstrap'
        },
        'validateunobtrusive':{
          deps:['validate'],
          exports: 'validateunobtrusive'
        }
      }
    });

配置好后,在页面中require,此时点击submit按钮提交表单,各js就开始作用了。但是除了焦点会落到第一个校验失败的控件上,似乎并没有其它效果,连jquery.validate默认的在控件后面展示错误信息(errorPlacement函数)都没有了,are you kidding me?其实这是因为jquery.validate.unobtrusive覆盖了errorPlacement配置项(看源码中的attachValidation函数),对我们来说反而省了一道工序。由于tooltip的html标记是由bootstrap动态生成的,所以errorPlacement并不适合我们,参考本文开头的链接,选择覆写showErrors函数,核心代码如下(tooltipvalidator.js):

define(['validateunobtrusive'], function () {

  function TooltipValidator() {}

  TooltipValidator.prototype = {
    init: function (validatorOptions, tooltipOptions) {
      tooltipOptions = tooltipOptions || {};
      validatorOptions = validatorOptions || {};

      this._tooltipOptions = $.extend({}, {
        placement: 'top'
      }, tooltipOptions, { animation: false });

      this._validatorOptions = $.extend({}, {

        //errorPlacement: function (error, element) {
        //  // do nothing
        //},

        showErrors: function (errorMap, errorList) {
          for (var i = 0; i < this.successList.length; i++) {
            var success = this.successList[i];
            $(this.successList[i]).tooltip('destroy');
            $(this.successList[i]).parents('div.form-group').removeClass('has-error');
          }
          for (var i = 0; i < errorList.length; i++) {
            var errorElement = $(errorList[i].element);
            errorElement.parents('div.form-group').addClass('has-error');
            errorElement.attr('data-original-title', errorList[i].message).tooltip('show');
          }
        },

        submitHandler: function (form) {
          return false;
        }

      }, validatorOptions)

      this._configTooltip();
      this._configValidator();
    },

    _configTooltip: function () {
      $('[data-val="true"]').tooltip(this._tooltipOptions);
    },

    _configValidator: function () {
      $.validator.setDefaults(this._validatorOptions);
      $.validator.unobtrusive.parse(document);
    }
  }

  return new TooltipValidator();
});

这样我们就可以在require回调函数中执行tooltipvalidator.init,不需要另外再写逻辑,于是前端同学也开心的笑了。这里还有一处需要注意,大家看到第49行代码,这是初始化jquery.validate.unobtrusive的步骤。原本jquery.validate.unobtrusive在其代码中已经有$(function () { $jQval.unobtrusive.parse(document); });但是由于$.ready会在Dom元素加载完成后(题外话:不是渲染完成)就执行,因此它会在tooltipvalidator有机会_configValidator之前完成,导致咱们的配置项无效(如果是在单页无刷新应用中,会发现之后再次加载局部页时,配置项有效了,因为$.ready只在初次加载的时候执行,而require回调会每次加载都执行)。有两种解决方法:1、让jquery.validate.unobtrusive依赖tooltipvalidator;2、移除jquery.validate.unobtrusive中的$jQval.unobtrusive.parse(document);这里选择第2种。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
Javascript与vbscript数据共享
Jan 09 Javascript
js实时监听文本框状态的方法
Apr 26 Javascript
前台js改变Session的值(用ajax实现)
Dec 28 Javascript
js创建子窗口并且回传值示例代码
Jul 02 Javascript
H5用户注册表单页 注册模态框!
Sep 17 Javascript
浅述Javascript的外部对象
Dec 07 Javascript
JS中传递参数的几种不同方法比较
Jan 20 Javascript
javascript 判断一个对象为数组的方法
May 03 Javascript
Vue中使用canvas方法总结
Feb 12 Javascript
基于 jQuery 实现键盘事件监听控件
Apr 04 jQuery
ES6知识点整理之对象解构赋值应用示例
Apr 17 Javascript
简单了解JavaScript弹窗实现代码
May 07 Javascript
JS触摸屏网页版仿app弹窗型滚动列表选择器/日期选择器
Oct 30 #Javascript
js模式化窗口问题![window.dialogArguments]
Oct 30 #Javascript
Chrome不支持showModalDialog模态对话框和无法返回returnValue问题的解决方法
Oct 30 #Javascript
原生JS版和jquery版实现checkbox的全选/全不选/点选/行内点选(Mr.Think)
Oct 29 #Javascript
JavaScript计算值然后把值嵌入到html中的实现方法
Oct 29 #Javascript
JS给Array添加是否包含字符串的简单方法
Oct 29 #Javascript
浅谈js对象属性 通过点(.) 和方括号([]) 的不同之处
Oct 29 #Javascript
You might like
PDO版本问题 Invalid parameter number: no parameters were bound
2013/01/06 PHP
淘宝ip地址查询类分享(利用淘宝ip库)
2014/01/07 PHP
php冒泡排序与快速排序实例详解
2015/12/07 PHP
PHP中substr函数字符串截取用法分析
2016/01/07 PHP
完美利用Yii2微信后台开发的系列总结
2016/07/18 PHP
laravel unique验证、确认密码confirmed验证以及密码修改验证的方法
2019/10/16 PHP
精通Javascript系列之数据类型 字符串
2011/06/08 Javascript
JQuery扩展插件Validate—4设置错误提示的样式
2011/09/05 Javascript
JQuery入门——用映射方式绑定不同事件应用示例
2013/02/05 Javascript
js数组的操作详解
2013/03/27 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
点击按钮自动加关注的代码(sina微博/QQ空间/人人网/腾讯微博)
2014/01/02 Javascript
jQuery如何实现点击页面获得当前点击元素的id或其他信息
2014/01/09 Javascript
javascript中判断json的方法总结
2015/08/27 Javascript
JavaScript 巧学巧用
2017/05/23 Javascript
浅谈Koa服务限流方法实践
2017/10/23 Javascript
使用vue-cli+webpack搭建vue开发环境的方法
2017/12/22 Javascript
JS与jQuery实现ListBox上移,下移,左移,右移操作功能示例
2018/05/31 jQuery
vue props传值失败 输出undefined的解决方法
2018/09/11 Javascript
kafka调试中遇到Connection to node -1 could not be established. Broker may not be available.
2019/09/17 Javascript
解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突问题
2020/07/24 Javascript
如何手动实现一个 JavaScript 模块执行器
2020/10/16 Javascript
Python实现视频下载功能
2017/03/14 Python
Python3.5.3下配置opencv3.2.0的操作方法
2018/04/02 Python
PyTorch上实现卷积神经网络CNN的方法
2018/04/28 Python
Python实现程序判断季节的代码示例
2019/01/28 Python
2019 Python最新面试题及答案16道题
2019/04/11 Python
python实现UDP协议下的文件传输
2020/03/20 Python
jupyter notebook读取/导出文件/图片实例
2020/04/16 Python
Python将QQ聊天记录生成词云的示例代码
2021/02/10 Python
HTML5自定义data-* data(obj)属性和jquery的data()方法的使用
2012/12/13 HTML / CSS
《彭德怀和他的大黑骡子》教学反思
2014/04/12 职场文书
读书伴我成长演讲稿
2014/05/07 职场文书
大学第二课堂活动总结
2014/07/08 职场文书
2014领导干部学习焦裕禄同志先进事迹思想汇报
2014/09/19 职场文书
剑指Offer之Java算法习题精讲二叉树的构造和遍历
2022/03/21 Java/Android