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 相关文章推荐
常见浏览器多长时间会提示“脚本运行时间过长”总结
Apr 29 Javascript
jQuery的:parent选择器定义和用法
Jul 01 Javascript
js识别uc浏览器的代码
Nov 06 Javascript
input file样式修改以及图片预览删除功能详细概括(推荐)
Aug 17 Javascript
分分钟学会vue中vuex的应用(入门教程)
Sep 14 Javascript
基于webpack 实用配置方法总结
Sep 28 Javascript
Node.js使用cookie保持登录的方法
May 11 Javascript
angularJs中ng-model-options设置数据同步的方法
Sep 30 Javascript
TypeScript中的方法重载详解
Apr 12 Javascript
vue动态配置模板 'component is'代码
Jul 04 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
Nov 01 jQuery
Vue+ElementUI table实现表格分页
Dec 14 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
利用中国天气预报接口实现简单天气预报
2014/01/20 PHP
php采用curl模仿登录人人网发布动态的方法
2014/11/07 PHP
cakephp2.X多表联合查询join及使用分页查询的方法
2017/02/23 PHP
PHP实现的XXTEA加密解密算法示例
2018/08/28 PHP
静态页面下用javascript操作ACCESS数据库(读增改删)的代码
2007/05/14 Javascript
JavaScript DOM学习第八章 表单错误提示
2010/02/19 Javascript
javascript中兼容主流浏览器的动态生成iframe方法
2014/05/05 Javascript
Javascript函数式编程简单介绍
2015/10/11 Javascript
Vue2实现组件props双向绑定
2016/12/02 Javascript
使用openSpeDiv方法实现Ecshop登录弹窗框效果
2017/03/13 Javascript
JS动态添加的div点击跳转到另一页面实现代码
2017/09/30 Javascript
Vue在页面数据渲染完成之后的调用方法
2018/09/11 Javascript
使用微信小程序开发弹出框应用实例详解
2018/10/18 Javascript
vue 使用高德地图vue-amap组件过程解析
2019/09/07 Javascript
Python程序员开发中常犯的10个错误
2014/07/07 Python
python3 实现验证码图片切割的方法
2018/12/07 Python
解决pyinstaller打包pyqt5的问题
2019/01/08 Python
基于Django的乐观锁与悲观锁解决订单并发问题详解
2019/07/31 Python
Python 开发工具PyCharm安装教程图文详解(新手必看)
2020/02/28 Python
TensorFlow固化模型的实现操作
2020/05/26 Python
无需压缩软件,用python帮你操作压缩包
2020/08/17 Python
轻松掌握CSS3中的字体大小单位rem的使用方法
2016/05/24 HTML / CSS
购买限量版收藏品、珠宝和礼品:Bradford Exchange
2016/09/23 全球购物
aden + anais官方网站:婴儿襁褓、毯子、尿布和服装
2017/06/21 全球购物
英国领先的餐饮折扣俱乐部:Gourmet Society
2020/07/26 全球购物
如果Session Bean得Remove方法一直都不被调用会怎么样
2012/07/14 面试题
领导干部“四风”问题批评与自我批评材料
2014/09/24 职场文书
院党委组织查摆问题对照检查材料思想汇报2014
2014/10/08 职场文书
2014年纪检监察工作总结
2014/11/11 职场文书
好媳妇事迹材料
2014/12/24 职场文书
2015年教师节贺卡寄语
2015/03/24 职场文书
毕业答辩开场白范文
2015/05/27 职场文书
中秋节感想
2015/08/10 职场文书
2019请假条的基本格式及范文!
2019/07/05 职场文书
一篇文章告诉你如何实现Vue前端分页和后端分页
2022/02/18 Vue.js
HTML常用标签超详细整理
2022/03/19 HTML / CSS