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高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js
Aug 14 Javascript
iframe子父页面调用js函数示例
Nov 07 Javascript
JavaScript中的replace()方法使用详解
Jun 06 Javascript
AngularJs  unit-testing(单元测试)详解
Sep 02 Javascript
BootStrap实现鼠标悬停下拉列表功能
Feb 17 Javascript
老生常谈js中的MVC
Jul 25 Javascript
vue 实现 ios 原生picker 效果及实现思路解析
Dec 06 Javascript
通过javascript实现段落的收缩与展开
Jun 26 Javascript
弱类型语言javascript开发中的一些坑实例小结【变量、函数、数组、对象、作用域等】
Aug 07 Javascript
layui select 禁止点击的实现方法
Sep 05 Javascript
node.js使用fs读取文件出错的解决方案
Oct 23 Javascript
vue 实现基础组件的自动化全局注册
Dec 25 Vue.js
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
国产动画《伍六七》原声大碟大卖,啊哈娱乐引领音乐赋能IP的新尝试
2020/03/08 国漫
php截取utf-8中文字符串乱码的解决方法
2010/03/29 PHP
php绘制一个扇形的方法
2015/01/24 PHP
JavaScript DOM 学习第三章 内容表格
2010/02/19 Javascript
jQuery中创建实例与原型继承揭秘
2011/12/21 Javascript
jquery和css3实现的炫酷时尚的菜单导航
2014/09/01 Javascript
jQuery实现可用于博客的动态滑动菜单
2015/03/09 Javascript
JavaScript之Object类型介绍
2015/04/01 Javascript
jQuery+ajax实现文章点赞功能的方法
2015/12/31 Javascript
JS使用onerror捕获异常示例
2016/08/03 Javascript
jquery.validate表单验证插件使用方法解析
2016/11/07 Javascript
详解jQuery同步Ajax带来的UI线程阻塞问题及解决办法
2017/08/09 jQuery
Vue单文件组件基础模板小结
2017/08/10 Javascript
Angular项目如何升级至Angular6步骤全纪录
2018/09/03 Javascript
世界上最短的数字判断js代码
2019/09/09 Javascript
利用Python的Flask框架来构建一个简单的数字商品支付解决方案
2015/03/31 Python
Python守护进程和脚本单例运行详解
2017/01/06 Python
在python中使用正则表达式查找可嵌套字符串组
2017/10/24 Python
Python数据结构之哈夫曼树定义与使用方法示例
2018/04/22 Python
Python爬虫 bilibili视频弹幕提取过程详解
2019/07/31 Python
python实现对列表中的元素进行倒序打印
2019/11/23 Python
python GUI库图形界面开发之PyQt5打开保存对话框QFileDialog详细使用方法与实例
2020/02/27 Python
python实现文字版扫雷
2020/04/24 Python
python 实现朴素贝叶斯算法的示例
2020/09/30 Python
自考生毕业自我鉴定
2013/10/10 职场文书
自我推荐书
2013/12/04 职场文书
计算机专业学生的自我评价
2013/12/15 职场文书
运动会表扬稿大全
2014/01/16 职场文书
平面设计专业大学生职业规划书
2014/03/12 职场文书
市场营销战略计划书
2014/05/06 职场文书
小学生九一八纪念日83周年演讲稿500字
2014/09/17 职场文书
喋血孤城观后感
2015/06/08 职场文书
教师网络培训心得体会
2016/01/09 职场文书
2016五四青年节活动总结范文
2016/04/06 职场文书
python基于tkinter制作无损音乐下载工具
2021/03/29 Python
python中Pyqt5使用Qlabel标签播放视频
2022/04/22 Python