项目需要,使用到了CKEditor编辑器。这是个很不错的富文本编辑器,但是当它绑定的字段需要进行模型验证的时候,却会出现验证失效的问题。因此本文旨在记录这个问题和给出解决办法。以下以ValidationAttribute和jQuery Validate2中验证方式为例。测试项目包含3个页面:Index.cshtml(包含2个部分视图)、Add.cshtml(添加页)、Companies(列表页,仅为展示数据);一个模型(Company)。项目功能截图如下:

---------------------------------------------------------------------------List

---------------------------------------------------------------------------Add

Part 1 使用ValidationAttribute进行验证

模型字段的属性设置就不说了,所有字段均不为空,测试Company代码如下:

public class Company
{
public Guid CompanyID { get; set; }
[Display(Name = "公司名")]
[Required(ErrorMessage = "公司名称不能为空")]
public string CompanyName { get; set; }
[Display(Name = "公司地址")]
[Required(ErrorMessage = "公司地址不能为空")]
public string CompanyAddress { get; set; }
[Display(Name = "公司简介")]
[Required(ErrorMessage = "公司简介不能为空")]
public string CompanyProfile { get; set; } public static List<Company> Companies = new List<Company>() {
new Company{CompanyID=new Guid("{CC1088BC-EF53-45C0-8D95-54F7665834C0}") ,CompanyName="百度",CompanyAddress="北京市海淀区上地十街10号",CompanyProfile="百度"},
new Company{CompanyID=new Guid("{6DC7545F-CA7C-49E8-B88E-447F43CBA7AE}") ,CompanyName="腾讯",CompanyAddress="中国广东省深圳市南山区深南大道10000号腾讯大厦",CompanyProfile="腾讯"},
new Company{CompanyID=new Guid("{EFA27D91-44CE-477E-8B19-BB6A1A785EC1}"), CompanyName="阿里巴巴",CompanyAddress="杭州市滨江区网商路699号",CompanyProfile="阿里"}
};
}

Add.cshtml代码如下:

@model Laibxw.Models.Company
@{
ViewBag.Title = "CompanyAdd";
Layout = null;
} <h4></h4>
@using (Html.BeginForm("Add", "Test", FormMethod.Post, new { @class = "form-horizontal", role = "form", id = "add" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@*@Html.ValidationSummary(true)*@
<div class="form-group">
@Html.LabelFor(model => model.CompanyName, new { @class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:5px;">
@Html.TextBoxFor(model => model.CompanyName)
@Html.ValidationMessageFor(model => model.CompanyName)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.CompanyAddress, new { @class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:5px;">
@Html.TextBoxFor(model => model.CompanyAddress)&nbsp;&nbsp;
@Html.ValidationMessageFor(model => model.CompanyAddress)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.CompanyProfile, new { @class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:5px;">
@Html.TextAreaFor(model => model.CompanyProfile, new { @class = "ckeditor" })
@Html.ValidationMessageFor(model => model.CompanyProfile)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="提交" class="btn btn-default" />
</div>
</div>
</div>
}
<style>
.error {
color: #b94a48;
font-weight: inherit;
}
</style> <script src="~/Scripts/jquery.validate.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#add").submit(function () {
var _this = $(this);
$.post(_this.attr('action'), _this.serialize(), function (data) {
if (data.error == "0") {
location.href = "/Test/Index";
} else {
$('#tab2').html(data) //3.出来样式改变了
}
});
return false;
});
});
</script>

后台Controller如下:

    public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
return View();
} public ActionResult Companies()
{
var companies = Company.Companies;
return View(companies);
} public ActionResult Add()
{
return View();
} [HttpPost]
public ActionResult Add(Company model)
{
if (!ModelState.IsValid) return PartialView(model);
model.CompanyID = new Guid("{F419EC35-F070-491C-B38D-73FC4A24F253}");
Company.Companies.Add(model);
return Json(new { error = });
}
}

运行示例添加一个Company:

发现果真无法验证,而且由于使用了部分视图,CKEditor被还原成了默认的textarea。有点糟糕!

Part 2 使用ValidationAttribute进行验证

那么使用jQuery Validate呢?于是添加了jq脚本:

<script src="~/Scripts/jquery.validate.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#add").submit(function () {
var _this = $(this);
if (validater.form()) { //验证成功
$.post(_this.attr('action'), _this.serialize(), function (data) {
if (data.error == "") {
location.href = "/Test/Index";
} else {
$('#tab2').html(data) //3.出来样式改变了
}
});
}
return false;
}); //验证
var validater = $("#add").validate({ //1.解决所谓的jquery.validate.js失效的说法
rules: {
CompanyName: {
required: true,
},
CompanyAddress: {
required: true,
},
CompanyProfile: {
required: true,
}
},
messages: {
CompanyName: {
required: "公司名称不能为空",
},
CompanyAddress: {
required: "公司地址不能为空",
},
CompanyProfile: {
required: "公司简介不能为空",
}
}
});
});
</script>

运行效果和上面的是一样的。

那么之所以出现这个状况,其实是由于CKEditor没有及时将用户输入更新到相应的textarea。如果你测试会发现,当你第二次提交表单的时候,是可以获取获取到值的。那么解决这个问题的办法是这个样子的,当提交表单之前的时候及时更新textarea的值:

//先更新textarea值
for (instance in CKEDITOR.instances)
CKEDITOR.instances[instance].updateElement();

值是获取到了,但是用jQuery.validate仍然没有效果(网上看了很多解决办法,貌似只看到一个回到是对的),解决办法是在客户端验证的时候加上ignore: '':

另外当使用纯后端验证的时候,CKEditor会被“打回原形”。解决的办法是在验证不通过返回部分视图之后加上这么一句:

$('textarea.ckeditor').each(function () {
var $textarea = $(this);
CKEDITOR.replace($textarea.attr("id"))
});

但是这样还是会有一个小的缺陷:

就是先显示之前的textarea标签,然后立即变为CKEditor。开始以为是因为这个是在返回部分视图并将数据展示到#tab2之后发生的,后来发现,即使是在部分视图中加载好也会出现这样的问题。

单独测试CKEditor不难发现经过服务器端验证使用ValidationMessageFor来显示错误消息就会出现这个状况,其实原因很简单,你刷新页面就会发现是由于CKEditor插件略微有些延迟。所以它首先会显示原生态的textarea(没通过验证会有错误提示),然后CKEditor才会应用于textarea。这确实是个头痛的问题。

这个问题暂时没有找到合适的解决方案。只有采取jQuery.validate.js配合手写验证规则的前端验证来解决。关于服务器端验证的办法提供一个不是很完美的办法:

$('textarea.ckeditor').each(function () {
var $textarea = $(this);
var error = $textarea.parent().find('span');
error.hide();
CKEDITOR.replace($textarea.attr("id"));
$textarea.hide(); //暂时隐藏掉error
setTimeout(function () {
error.show();
}, 20);
});

问题处理代码:

@model Models.Company
@{
ViewBag.Title = "CompanyManagement";
Layout = null;
}
@Styles.Render("~/Content/Plan_admin.css")
@Styles.Render("~/Content/lbw_css.css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/exp-js")
@Scripts.Render("~/bundles/bootstrap")
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/bootstrap.min")
<div class="ProductAdd">
<div class='container-fluid' style=" width:650px;float:left;margin-left:100px; margin-top:100px;">
<div class='tabbable tabs-left'>
<ul class='nav nav-tabs nav-pills top-size' role="tablist">
<li class='active' role="presentation"><a href='#tab1' data-toggle='tab' style="font-size:14px;font-family:Arial;">公司列表</a></li>
<li><a href='#tab2' data-toggle='tab' style="font-size:14px;">添加公司</a></li>
</ul>
<div class='tab-content'>
<div class='tab-pane active' id='tab1'>
@Html.Action("Companies", "Test")
</div>
<div class='tab-pane' id='tab2'>
@Html.Action("Add", "Test")
</div>
</div>
<div style="clear:both"></div>
</div>
</div>
</div>
<script src="~/Scripts/jquery.validate.js"></script> <script type="text/javascript">
$(document).ready(function () {
$("#tab2 form").submit(function () {
//先更新textarea值
for (instance in CKEDITOR.instances)
CKEDITOR.instances[instance].updateElement();
var _this = $(this);
if (validater.form()) {
$.post(_this.attr('action'), _this.serialize(), function (data) {
if (data.error == "") {
location.href = "/Test/Index";
} else {
//问题出现在ckeditor对textare的改变有延迟
$('#tab2').empty().html(data) //3.出来样式改变了
$('textarea.ckeditor').each(function () {
var $textarea = $(this);
var span = $textarea.parent().find('span');
span.hide();
CKEDITOR.replace($textarea.attr("id"));
$textarea.hide();
setTimeout(function () {
span.show();
}, );
});
}
});
}
return false;
});
//验证
var validater = $("#tab2 form").validate({
rules: {
CompanyName: {
required: true,
},
CompanyAddress: {
required: true,
},
CompanyProfile: {
required: true,
}
},
ignore: '', //不能少
messages: {
CompanyName: {
required: "公司名称不能为空",
},
CompanyAddress: {
required: "公司地址不能为空",
},
CompanyProfile: {
required: "公司简介不能为空",
}
}
})
});
</script>

当ASP.NET MVC模型验证遇上CKEditor的更多相关文章

  1. ASP.NET MVC - 模型验证

    ASP.NET MVC - 模型验证(Model verification) 模型验证原理浅析 模型验证用到了模型绑定器.模型验证器(System.Web.Mvc.DataAnnotationsMod ...

  2. asp.net mvc 模型验证组件——FluentValidation

    asp.net mvc 模型验证组件——FluentValidation 示例 using FluentValidation; public class CustomerValidator: Abst ...

  3. Asp.Net MVC 模型验证详解-实现客户端、服务端双重验证

    概要 在asp.net webform开发中经常会对用户提交输入的信息进行校验,一般为了安全起见大家都会在客户端进行Javascript(利于交互).服务端双重校验(安全).书写校验代码是一个繁琐的过 ...

  4. ASP.NET没有魔法——ASP.NET MVC 模型验证

    在前面的文章中介绍了用户的注册及登录功能,在注册用户时可以通过代码的形式限制用户名及密码的格式,如果不符合要求那么就无法完成操作,如下图: 该功能的原理是Identity基于的Entity Frame ...

  5. asp.net mvc 模型验证注解,表单提交

    一.添加模型 public class Account { public int ID { get; set; } [Display(Name = "姓名")] //设置要显示的字 ...

  6. asp.net mvc 模型验证-最舒服的验证方式

    在院子里发现 http://www.cnblogs.com/yangecnu/p/3759784.html 模型验证方法 1. 一般方法 繁琐, 无数的if else, 在炎炎夏天,我见过一个验证方法 ...

  7. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  8. ASP.NET MVC Model验证(四)

    ASP.NET MVC Model验证(四) 前言 本篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而Mod ...

  9. ASP.NET MVC 5 - 验证编辑方法(Edit method)和编辑视图(Edit view)

    在本节中,您将验证电影控制器生成的编辑方法(Edit action methods)和视图.但是首先将修改点代码,使得发布日期属性(ReleaseDate)看上去更好.打开Models \ Movie ...

随机推荐

  1. 【锋利的JQuery-学习笔记】Tootip(提示框)

    效果图: 1.当鼠标移动到超链接时,有提示框. 2..当鼠标移动到图片动画旋转 html: <div id="jnNotice"> <div id="j ...

  2. wordpress数据库优化wp_posts表 OPTIMIZE

    wordpress数据库优化wp_posts表 对 MySQL 数据记录进行插入.更新或删除时,会占有不同大小的空间,记录就会变成碎片,且留下空闲的空间.就像具有碎片的磁盘,会降低性能,需要整理,因此 ...

  3. 山寨小小军团开发笔记 之 Arrow Projectile

    好久没怎么更新博客了,今天抽空来一篇,讨论一下弓箭的轨迹生成. 一.原理 弓箭的轨迹本质就是一个数学问题,使用一个 bezier 曲线公式就可以插值生成.得到轨迹后,做一个lookAt就可以了. 二. ...

  4. 为什么android的R类要定义成16进制

    联想到c语言中的宏定义:我想是一个原因 如: #define SDL_INIT_TIMER 0x00000001 #define SDL_INIT_AUDIO 0x00000010 #define S ...

  5. C#中的文件操作

    在.NET Framework 中进行的所有输入和输出工作都要用到流(stream) 有两种类型的流: 输出流:当向某些外部目标写入数据时,就要用到输出流(将数据写入到文件中). 输入流:用于将数据读 ...

  6. TDD三个阶段

    TDD的三个阶段 红灯.绿灯.重构 :明确了实施TDD所要遵循的工作流 (需求--->测试-->代码[重构]) 红灯阶段:      为不存在的代码编写测试 绿灯阶段:      仅编写适 ...

  7. cojs 疯狂的求和问题 解题报告

    QAQ 好久不在cojs上出题了 最近学了点新科技,于是就做成题来分享了 这道题是要求simga(i^k) 那么就先说说部分分的算法吧: 10分: 直接暴力就可以了,时间复杂度O(nlogk) 30分 ...

  8. ASP.NET连接数据库并获取数据

    关键词:连接对象的用法SqlConnection,SqlCommand,SqlDataAdapter *数据访问方式的写法 工具/原料 VS SQL SERVER 2012 R2 方法/步骤1: 1. ...

  9. 从svn删除文件夹和文件

    由于项目开始放在自己项目组的一个服务器上,而且svn也是自己在该服务器上搭建的,但是不知道是什么原因,svn上的代码被误删了.为了更稳定地使用svn,所以使用公司的svn来管理代码. 运维将不是最新版 ...

  10. C程序的内存分配

    一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...