透過AJAX接收ModelState Errors顯示於對應欄位中
前言
在執行表單資料驗證時,前端大多透過ASP.NET MVC的Html.Helper產出data-val-*屬性(依據ViewModel Attribute設定),再搭配jQuery來進行Client端資料檢核;但若牽涉複雜商業邏輯檢核時就會交由後端驗證來處理,而驗證失敗的訊息會透過ModelState.AddModelError(key, errorMessage)方法來新增,最後在產生View畫面時會依照key找尋對應欄位來加註此errorMessage做顯示。如今在AJAX情況下,後端驗證所新增的ModelState Error方式沒變,但此時就必須要自行處理前端誤訊息的顯示工作,以下將進行實作的介紹。
實作方法
舉個簡單的例子,有一個使用者註冊介面,在輸入完畢後會以AJAX方式送出資料至後端,而在後端將驗證核該UserId是否已存在系統中,若存在的話就顯示錯誤訊息於UserId欄位下方,示意圖如下。
檢視一下View代碼,首先就是建立一個id為RegisterForm的表單,而前端驗證一如往常透過Http.Editor與Http.ValidationMessageFor兩個Html.Helper來產出相對應View Model屬性之Html元素。
@using (Html.BeginForm("SignUp", "User", FormMethod.Post, new { id = "RegisterForm" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<!-- input user id -->
<div class="form-group">
@Html.LabelFor(model => model.SingupUser.SysUserId)
<div style="margin-bottom: 5px" class="col-md-9">
@Html.EditorFor(model => model.SingupUser.SysUserId)
@Html.ValidationMessageFor(model => model.SingupUser.SysUserId, "", new { @class = "text-danger" })
</div>
</div>
<!-- input user email -->
<div class="form-group">
@Html.LabelFor(model => model.SingupUser.Email)
<div style="margin-bottom: 5px" class="col-md-9">
@Html.EditorFor(model => model.SingupUser.Email)
@Html.ValidationMessageFor(model => model.SingupUser.Email, "", new { @class = "text-danger" })
</div>
</div>
<!-- 略 -->
<!-- 略 -->
<!-- Sign up button -->
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<input type="button" id="submitButton" value="Sign Up Ajax" class="btn btn-info" />
</div>
</div>
}
產出畫面及對應HTML碼如下 (HttpHelper產出UserId輸入方塊,名稱為SignupUser.SysUserId)
在Controller的SignUpAjax Action中檢查UserId是否存在,若是則透過ModelState.AddModelError()新增錯誤訊息;最後擷取所有Model Error資訊放置於Dcitionary容器中,連同其他資訊一併回應前端。
SignUpAjax Action代碼如下
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SignUpAjax(UserLoginViewModel viewModel)
{
bool isSuccess = true;
if (ModelState.IsValid)
{
// check if the same member id exists in system
if (_serviceFactory.UserService.GetUserById(viewModel.SingupUser.SysUserId) != null)
{
ModelState.AddModelError("SingupUser.SysUserId", "The user id has already existed in system");
isSuccess = false;
}
if (isSuccess)
{
// register user to db
// ...
}
}
var returnData = new
{
// 成功與否
IsSuccess = isSuccess,
// ModelState錯誤訊息
ModelStateErrors = ModelState.Where(x => x.Value.Errors.Count > 0)
.ToDictionary(k => k.Key, k => k.Value.Errors.Select(e => e.ErrorMessage).ToArray())
};
return Content(Newtonsoft.Json.JsonConvert.SerializeObject(returnData), "application/json");
}
最後只要在javacript中,將傳回的Model錯誤訊息顯示出來就大功告成了
// submit data to server
$('#submitButton').click(function () {
var myForm = $("#RegisterForm");
var validator = myForm.validate();
if (myForm.valid()) {
var dataForm = myForm.serialize();
$.ajax({
type: 'POST',
url: '@Url.Action("SignUpAjax", "User")',
data: dataForm,
cache: false,
async: false,
success: function (data) {
if (data.IsSuccess) {
alert('register done');
window.location = '@Url.Action("Login", "User")';
} else {
if (data.ModelStateErrors != null) {
// show model state error
validator.showErrors(data.ModelStateErrors);
alert('please check all required info');
} else {
alert('register fail');
}
}
}
});
}
});
測試輸入已存在UserId並點選Sign Up Ajax按鍵後,在後端新增之Model Error訊息正確顯示於對應位置上。
希望此篇文章可以幫助到需要的人
若內容有誤或有其他建議請不吝留言給筆者喔 !