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 检测、添加、移除样式(className)函数代码
Sep 08 Javascript
jQueryUI的Dialog的简单封装
Jun 07 Javascript
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
Jan 13 Javascript
js取两个数组的交集|差集|并集|补集|去重示例代码
Aug 07 Javascript
JS的参数传递示例介绍
Feb 08 Javascript
让checkbox不选中即将选中的checkbox不选中
Jul 11 Javascript
javascript跨域原因以及解决方案分享
Apr 08 Javascript
JavaScript和HTML DOM的区别与联系及Javascript和DOM的关系
Nov 15 Javascript
详解AngularJS Filter(过滤器)用法
Dec 28 Javascript
实例详解jQuery的无new构建
Aug 02 Javascript
AngularJS 防止页面闪烁的方法
Mar 09 Javascript
vue2.0模拟锚点的实例
Mar 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
php封装一个异常的处理类
2017/06/08 PHP
PHP实现的简单在线计算器功能示例
2017/08/02 PHP
javascript 限制输入脚本大全
2009/11/03 Javascript
Jquery Ajax学习实例 向页面发出请求,返回XML格式数据
2010/03/14 Javascript
javascript 学习笔记(onchange等)
2010/11/14 Javascript
jQuery对Select的操作大集合(收藏)
2013/12/28 Javascript
基于jQuery实现的仿百度首页滑动选项卡效果代码
2015/11/16 Javascript
基于jQuery和CSS3制作响应式水平时间轴附源码下载
2015/12/20 Javascript
JS中创建函数的三种方式及区别
2016/03/13 Javascript
JavaScript中的this使用详解
2016/07/27 Javascript
AngularJs Understanding the Controller Component
2016/09/02 Javascript
DOM事件探秘篇
2017/02/15 Javascript
原生js jquery ajax请求以及jsonp的调用方法
2017/08/04 jQuery
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
echarts鼠标覆盖高亮显示节点及关系名称详解
2018/03/17 Javascript
Vue自定义指令封装节流函数的方法示例
2018/07/09 Javascript
angular2 ng2-file-upload上传示例代码
2018/08/23 Javascript
微信小程序实现单选选项卡切换效果
2020/06/19 Javascript
微信小程序 wepy框架与iview-weapp的用法详解
2019/04/10 Javascript
微信小程序开发之左右分栏效果的实例代码
2019/05/20 Javascript
vue 封装面包屑组件教程
2020/11/16 Javascript
如何运行Python程序的方法
2013/04/21 Python
浅谈Python 的枚举 Enum
2017/06/12 Python
Odoo中如何生成唯一不重复的序列号详解
2018/02/10 Python
详解小白之KMP算法及python实现
2019/04/04 Python
python能做什么 python的含义
2019/10/12 Python
python 的topk算法实例
2020/04/02 Python
Python类成员继承重写的实现
2020/09/16 Python
PyCharm中关于安装第三方包的三个建议
2020/09/17 Python
Swanson中国官网:美国斯旺森健康产品公司
2021/03/01 全球购物
OnePlus加拿大官网:中国国际化手机品牌
2020/10/13 全球购物
某个公司的Java笔面试题
2016/03/11 面试题
利用指针变量实现队列的入队操作
2012/04/07 面试题
科研先进个人典型材料
2014/01/31 职场文书
2015年秘书个人工作总结
2015/04/25 职场文书
庆祝教师节主持词
2015/07/06 职场文书