本文主要體驗通過jQuery非同步驗證。
在很多的教材和案例中,MVC驗證都是通過提交表單進行的。通過提交表單,可以很容易獲得驗證出錯資訊。因為,無論是客戶端驗證還是服務端驗證,總能找到與Model屬性或驗證特性對應的html元素和屬性,並把錯誤資訊顯示出來。可是,在實際專案中,經常會遇到需要非同步提交的情況。那麼,如何把服務端的驗證錯誤資訊傳遞給前端檢視呢?
□ 思路
1、服務端的驗證錯誤資訊是可以收集起來的以json形式傳遞個檢視的。
2、服務端把錯誤資訊存放在一個字典集合Dictionary<string, object>,讓key是屬性名,value是錯誤資訊。
3、前臺檢視中,顯示錯誤資訊的元素id,比方說是Err_Name,當遍歷從服務端傳來的字典集合時,取出key,然後把錯誤資訊動態賦值給$('#Err_' + key)。
View model
using System;
using System.ComponentModel.DataAnnotations;
namespace DataAnnotationAjax.Models
{
public class Student
{
public int Id { get; set; }
[Required(ErrorMessage = "姓名為必填項")]
[Display(Name = "姓名")]
public string Name { get; set; }
[Required(ErrorMessage = "分數是必選項")]
[Range(60, 100, ErrorMessage = "分數必須在60和100之間")]
[Display(Name = "分數")]
public int Score { get; set; }
[Display(Name = "招收日期")]
public DateTime Enrollment { get; set; }
}
}
模擬一個倉儲層,負責資料的初始化、新增和顯示
using System;
using System.Collections.Generic;
using DataAnnotationAjax.Models;
namespace DataAnnotationAjax.Service
{
public static class StudentRepository
{
private static int _idSeed = 1;
private static readonly List<Student> _students = new List<Student>();
static StudentRepository()
{
Random rand = new Random();
for (int i = 0; i < 3; i++)
{
var student = new Student();
int id = _idSeed++;
student.Id = id;
student.Name = "姓名" + id.ToString();
student.Score = (60 + Convert.ToInt16(rand.NextDouble()*40));
student.Enrollment = DateTime.Now;
_students.Add(student);
}
}
public static void AddStudent(Student stu)
{
stu.Id = _idSeed++;
stu.Enrollment = DateTime.Now;
_students.Add(stu);
}
public static List<Student> GetStudents()
{
return _students;
}
}
}
BaseController
前臺檢視為了顯示錯誤資訊等,需要控制器傳來的json可能包含如下構成:
1、是否驗證通過:這個bool值很容易通過ModelState拿到。
2、錯誤資訊的字典集合:每個控制器都有可能用到,可以把獲取錯誤資訊的字典集合方法放到一個基控制器中去。
3、再加一個福利:有時希望部分檢視以字串形式傳遞給某一檢視,那就把根據檢視名稱和model返回檢視字串的方法也放到基控制器中。
展開
HomeController
HomeController做了:
1、顯示一個非同步提交的檢視Index.cshtml
2、完成了驗證通過情況下的資料新增。
3、不管是否驗證通過,都要返回json字串。
using System.Web.Mvc;
using DataAnnotationAjax.Models;
using DataAnnotationAjax.Service;
namespace DataAnnotationAjax.Controllers
{
public class HomeController : BaseController
{
public ActionResult Index()
{
return View(StudentRepository.GetStudents());
}
[HttpPost]
public ActionResult AddStudent()
{
var student = new Student();
var valid = TryUpdateModel(student);
string studentPartialViewHtml = string.Empty;
if (valid)
{
StudentRepository.AddStudent(student);
var students = StudentRepository.GetStudents();
studentPartialViewHtml = RenderPartialViewToString("Students", students);
}
return Json(new {Valid = valid, Errors = GetErrorFromModelState(), StudentsPartial = studentPartialViewHtml});
}
}
}
部分檢視Students.cshtml
展開
Index.cshtml非同步提交的介面
@model IEnumerable<DataAnnotationAjax.Models.Student>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<style type="text/css">
.errormsg {
color: red;
}
</style>
<div>
<table cellpadding="0px">
<tr>
<td>姓名</td>
<td><input type="text" id="Name" /></td>
</tr>
<tr>
<td></td><td colspan="2"
id="Err_Name" class="errormsg"></td>
</tr>
<tr>
<td>分數</td>
<td><input type="text" id="Score" /></td>
<td>
<button id="btnAddStudent">新增學生</button>
<button id="btnClear">清空</button>
</td>
</tr>
<tr>
<td></td><td colspan="2"
id="Err_Score" class="errormsg"></td>
</tr>
</table>
</div>
<div id="divStudent">
@{Html.RenderPartial("Students",Model);}
</div>
@section scripts
{
<script type="text/javascript">
$(function() {
$('#btnAddStudent').click(function() {
var data = {
Name: $.trim($('#Name').val()),
Score: $.trim($('#Score').val())
};
$.ajax({
cache: false,
type: "POST",
url: '@Url.Action("AddStudent", "Home")',
data: data,
dataType: "json",
success: function(data) {
if (data.Valid) {
$('#divStudent').html(data.StudentsPartial);
$('input').val("");
return;
}
$.each(data.Errors, function(key, value) {
if (value != null) {
$('#Err_' + key).html(value[value.length - 1].ErrorMessage);
}
});
},
error: function(xhr) {
alert(xhr.responseText);
alert("資料沒有能提交到伺服器!");
}
});
});
$('#btnClear').click(function() {
$('.errormsg').html("");
$("input").val("");
});
$("input").keyup(function() {
var $errorDiv = $("#Err_" + this.id);
if ($errorDiv.html() !="") {
$errorDiv.html("");
}
});
});
</script>
}
幾個關鍵點:
1、顯示錯誤資訊的元素id的命名有講究的:Err_Name,Name與Model中的屬性一致。
2、遍歷服務端傳來的錯誤資訊字典集合時,對每個屬性,即key,拿的是最近一次錯誤:$('#Err_' + key).html(value[value.length - 1].ErrorMessage)。
沒有填寫資訊報錯:
填寫分數不在定義區間報錯:
全部填寫正確,驗證通過,把部分檢視以string形式返回並載入到頁面區域中: