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 检测浏览器类型和版本的代码
Sep 15 Javascript
深入理解JavaScript系列(44):设计模式之桥接模式详解
Mar 04 Javascript
JavaScript实现的经典文件树菜单效果
Sep 08 Javascript
JS实现日期时间动态显示的方法
Dec 07 Javascript
js实现目录链接,内容跟着目录滚动显示的简单实例
Oct 15 Javascript
vue组件间通信解析
Mar 01 Javascript
bootstrap弹出层的多种触发方式
May 10 Javascript
angular框架实现全选与单选chekbox的自定义
Jul 06 Javascript
JS 中使用Promise 实现红绿灯实例代码(demo)
Oct 20 Javascript
node.js制作一个简单的登录拦截器
Feb 10 Javascript
vue+koa2搭建mock数据环境的详细教程
May 18 Javascript
Vue中用JSON实现刷新界面不影响倒计时
Oct 26 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
网页游戏开发入门教程二(游戏模式+系统)
2009/11/02 PHP
PHP实现图片自动清理的方法
2015/07/08 PHP
php入门教程之Zend Studio设置与开发实例
2016/09/09 PHP
解决laravel资源加载路径设置的问题
2019/10/14 PHP
phpStudy vscode 搭建debug调试的教程详解
2020/07/28 PHP
JavaScript写的一个DIV 弹出网页对话框
2009/08/14 Javascript
用JQuery 判断某个属性是否存在hasAttr的解决方法
2013/04/26 Javascript
jQuery 淡出一个图像到另一个图像的实现代码
2013/06/12 Javascript
NodeJS url验证(url-valid)的使用方法
2013/11/18 NodeJs
js中事件的处理与浏览器对象示例介绍
2013/11/29 Javascript
Jquery响应回车键直接提交表单操作代码
2014/07/25 Javascript
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
jQuery 3.0十大新特性最终版发布
2016/07/14 Javascript
基于Vuejs实现购物车功能
2016/08/02 Javascript
vue.js表格分页示例
2016/10/18 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
layui表格checkbox选择全选样式及功能的实例
2018/03/07 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
2020/01/22 Javascript
微信小程序实现搜索框功能及踩过的坑
2020/06/19 Javascript
vue-video-player实现实时视频播放方式(监控设备-rtmp流)
2020/08/10 Javascript
Python的爬虫程序编写框架Scrapy入门学习教程
2016/07/02 Python
Python采用Django制作简易的知乎日报API
2016/08/03 Python
基于Django的python验证码(实例讲解)
2017/10/23 Python
python matplotlib中文显示参数设置解析
2017/12/15 Python
python机器学习理论与实战(五)支持向量机
2018/01/19 Python
树莓派用python中的OpenCV输出USB摄像头画面
2019/06/22 Python
python 抓包保存为pcap文件并解析的实例
2019/07/23 Python
Python爬虫学习之获取指定网页源码
2019/07/30 Python
python 三元运算符使用解析
2019/09/16 Python
Python sklearn中的.fit与.predict的用法说明
2020/06/28 Python
用pandas划分数据集实现训练集和测试集
2020/07/20 Python
西安当代医院管理研究院笔试题
2015/12/11 面试题
普通员工辞职信
2014/01/17 职场文书
建筑工地资料员岗位职责
2015/04/13 职场文书
《揠苗助长》教学反思
2016/02/20 职场文书
Android自定义双向滑动控件
2022/04/19 Java/Android