【问题标题】:How to display validation errors on page load?如何在页面加载时显示验证错误?
【发布时间】:2018-02-18 14:35:56
【问题描述】:

我正在我的应用程序中创建一个功能来处理上传的包含要导入的多条记录的 CSV 文件。需要验证数据,并且我想在单击 Import 按钮之前显示任何验证错误。高层计划:

  • 第 1 步:上传 CSV 文件
  • 第 2 步:显示 CSV 文件中的所有记录以及每条记录旁边的任何验证错误(缺少必填字段等)
  • 第 3 步:单击“导入”以实际导入有效记录。

这是我所拥有的简化版本:

用户视图模型

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; }
}

文件上传操作帖

[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>

问题

虽然这会生成一个漂亮的“预览”表,其中所有准备好的User 记录基本上都是准备好的隐藏字段行,但问题是它在导入按钮之前不会显示验证错误被点击。

如何在 return View('ImportPreview', newUsersToCreate) 返回视图后立即在每一行中显示每个字段的验证错误?

【问题讨论】:

  • 一个选项是添加一个脚本来在页面加载时验证表单 - $('form').valid();
  • 您也许还可以使用TryValidateModel(newUsersToCreate); in the controller after you populate it to add the ModelStateErrors`(未测试)
  • 我已经尝试了这两种方法,但都没有成功。不确定是否与这些隐藏字段有关。
  • 抱歉,没注意到。默认情况下,隐藏的输入不会在视图中验证,但您可以覆盖它
  • 请参阅this answer 以获取示例。但由于它们是隐藏的,用户无法编辑它们,所以不确定显示错误会有什么帮助

标签: c# asp.net-mvc validation unobtrusive-validation


【解决方案1】:

您可以在视图中通过检查$.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>

请注意,您可能包含一个(比如说)&lt;p id="error" style="display:none;"&gt; 标记,其中包含一个“一般”错误消息,表明数据无效并使用

if ($('form').valid()) {
    $('#error').show();
}

缺点是你需要包含原本不需要的 jQuery 脚本。

另一个选项是在控制器中对集合中的每个项目使用TryValidateObject 进行验证,并将任何错误添加到ModelState,这将显示在您的ValidationMessageFor() 占位符中。请注意以下假设 csvRecords 实现 IList&lt;T&gt; 以便您可以使用 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)并将其用于表格行的条件样式,并且您可以决定是否存在“太多' 错误,您可以只显示不同的视图,而不是呈现整个表格并显示可能重复的数百条错误消息

【讨论】:

  • 这正是我所需要的。我采用了第二种方法,因为在我的用例中,在控制器中处理验证并将预先验证的模型交付给视图似乎更好。谢谢!
猜你喜欢
  • 2017-10-21
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多