如何在页面加载时显示验证错误?
How to display validation errors on page load?
我正在我的应用程序中创建一项功能来处理上传的 CSV 文件,其中包含要导入的多条记录。数据需要验证,我想在单击 Import 按钮之前显示任何验证错误。高级计划:
- 第 1 步:上传 CSV 文件
- 第 2 步:显示 CSV 文件中的所有记录以及每条记录旁边的任何验证错误(缺少必填字段等)
- 第三步:点击"Import"以实际导入有效记录。
这是我所拥有的简化版本:
用户视图模型
public class UserViewModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(150)]
public string Email { get; set; }
[Required]
[StringLength(10)]
public string Phone { get; set; }
}
文件上传操作Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
foreach (var csvRecord in csvRecords)
{
newUsersToCreate.Add(new UserViewModel
{
Name = csvRecord.Name,
Email = csvRecord.Email,
Phone = csvRecord.Phone
});
}
return View("ImportPreview", newUsersToCreate);
}
查看ImportPreview.cshtml
@model IEnumerable<App.ViewModels.UserViewModel>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "alert alert-danger", role = "alert" })
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Validation Errors</th>
</tr>
</thead>
<tbody>
@Html.EditorFor(model => model)
</tbody>
</table>
<button type="submit">Import</button>
}
UserViewModel.cshtml
的编辑器模板
@model App.ViewModels.UserViewModel
<tr>
<td>
@Html.HiddenFor(model => model.Name)
@Html.DisplayFor(model => model.Name)
</td>
<td>
@Html.HiddenFor(model => model.Email)
@Html.DisplayFor(model => model.Email)
</td>
<td>
@Html.HiddenFor(model => model.Phone)
@Html.DisplayFor(model => model.Phone)
</td>
<td>
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.Phone, "", new { @class = "text-danger" })
</td>
</tr>
问题
虽然这会生成一个很好的 "preview" table,所有准备好的 User
记录基本上都是准备好隐藏字段的行,但问题是它不会显示验证错误,直到单击 导入 按钮。
如何让它在 return View('ImportPreview', newUsersToCreate)
返回视图后立即在每一行中显示每个字段的验证错误?
您可以通过检查 $.validator
是否有效在视图中执行此操作。由于默认情况下不验证隐藏输入,因此您还需要覆盖验证器。在 jquery-{version}.js
、jquery.validate.js
和 jquery.validate.unobtrusive.js
脚本之后添加以下内容(但不在 $(document).ready()
中)
<script>
// override validator to include hidden inputs
$.validator.setDefaults({
ignore: []
});
// validate form and display errors
$('form').valid();
</script>
请注意,您可能包含一个(比如)<p id="error" style="display:none;">
标签,其中包含一个 'general' 错误消息,表明数据无效并使用
if ($('form').valid()) {
$('#error').show();
}
缺点是您需要包含 jQuery 否则不需要的脚本。
另一个选项是在控制器中对集合中的每个项目使用 TryValidateObject
进行验证,并将任何错误添加到 ModelState
,这将显示在您的 ValidationMessageFor()
占位符中。请注意以下假设 csvRecords
实现 IList<T>
以便您可以使用 for
循环。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
for (int i = 0; i < csvRecords.Count; i++)
{
UserViewModel model = new UserViewModel
{
Name = csvRecords[i].Name,
....
};
newUsersToCreate.Add(model);
// validate the model and include the collection indexer
bool isValid = ValidateModel(model, i));
}
return View("ImportPreview", newUsersToCreate);
}
private bool ValidateModel(object model, int index)
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model);
if (!Validator.TryValidateObject(model, context, validationResults, true))
{
foreach (var error in validationResults)
{
string propertyName = $"[{index}].{error.MemberNames.First()}";
ModelState.AddModelError(propertyName, error.ErrorMessage);
}
return false;
}
return true;
}
控制器代码的优点是您可以向视图模型添加额外的 属性(例如 bool IsValid
)并将其用于 table 行的条件样式,并且您可以决定如果存在 'too many' 错误,您可以只显示不同的视图,而不是呈现整个 table 并显示可能重复出现的数百条错误消息
我正在我的应用程序中创建一项功能来处理上传的 CSV 文件,其中包含要导入的多条记录。数据需要验证,我想在单击 Import 按钮之前显示任何验证错误。高级计划:
- 第 1 步:上传 CSV 文件
- 第 2 步:显示 CSV 文件中的所有记录以及每条记录旁边的任何验证错误(缺少必填字段等)
- 第三步:点击"Import"以实际导入有效记录。
这是我所拥有的简化版本:
用户视图模型
public class UserViewModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(150)]
public string Email { get; set; }
[Required]
[StringLength(10)]
public string Phone { get; set; }
}
文件上传操作Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
foreach (var csvRecord in csvRecords)
{
newUsersToCreate.Add(new UserViewModel
{
Name = csvRecord.Name,
Email = csvRecord.Email,
Phone = csvRecord.Phone
});
}
return View("ImportPreview", newUsersToCreate);
}
查看ImportPreview.cshtml
@model IEnumerable<App.ViewModels.UserViewModel>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "alert alert-danger", role = "alert" })
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Validation Errors</th>
</tr>
</thead>
<tbody>
@Html.EditorFor(model => model)
</tbody>
</table>
<button type="submit">Import</button>
}
UserViewModel.cshtml
的编辑器模板@model App.ViewModels.UserViewModel
<tr>
<td>
@Html.HiddenFor(model => model.Name)
@Html.DisplayFor(model => model.Name)
</td>
<td>
@Html.HiddenFor(model => model.Email)
@Html.DisplayFor(model => model.Email)
</td>
<td>
@Html.HiddenFor(model => model.Phone)
@Html.DisplayFor(model => model.Phone)
</td>
<td>
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
@Html.ValidationMessageFor(model => model.Phone, "", new { @class = "text-danger" })
</td>
</tr>
问题
虽然这会生成一个很好的 "preview" table,所有准备好的 User
记录基本上都是准备好隐藏字段的行,但问题是它不会显示验证错误,直到单击 导入 按钮。
如何让它在 return View('ImportPreview', newUsersToCreate)
返回视图后立即在每一行中显示每个字段的验证错误?
您可以通过检查 $.validator
是否有效在视图中执行此操作。由于默认情况下不验证隐藏输入,因此您还需要覆盖验证器。在 jquery-{version}.js
、jquery.validate.js
和 jquery.validate.unobtrusive.js
脚本之后添加以下内容(但不在 $(document).ready()
中)
<script>
// override validator to include hidden inputs
$.validator.setDefaults({
ignore: []
});
// validate form and display errors
$('form').valid();
</script>
请注意,您可能包含一个(比如)<p id="error" style="display:none;">
标签,其中包含一个 'general' 错误消息,表明数据无效并使用
if ($('form').valid()) {
$('#error').show();
}
缺点是您需要包含 jQuery 否则不需要的脚本。
另一个选项是在控制器中对集合中的每个项目使用 TryValidateObject
进行验证,并将任何错误添加到 ModelState
,这将显示在您的 ValidationMessageFor()
占位符中。请注意以下假设 csvRecords
实现 IList<T>
以便您可以使用 for
循环。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
for (int i = 0; i < csvRecords.Count; i++)
{
UserViewModel model = new UserViewModel
{
Name = csvRecords[i].Name,
....
};
newUsersToCreate.Add(model);
// validate the model and include the collection indexer
bool isValid = ValidateModel(model, i));
}
return View("ImportPreview", newUsersToCreate);
}
private bool ValidateModel(object model, int index)
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model);
if (!Validator.TryValidateObject(model, context, validationResults, true))
{
foreach (var error in validationResults)
{
string propertyName = $"[{index}].{error.MemberNames.First()}";
ModelState.AddModelError(propertyName, error.ErrorMessage);
}
return false;
}
return true;
}
控制器代码的优点是您可以向视图模型添加额外的 属性(例如 bool IsValid
)并将其用于 table 行的条件样式,并且您可以决定如果存在 'too many' 错误,您可以只显示不同的视图,而不是呈现整个 table 并显示可能重复出现的数百条错误消息