如何解决自定义服务器端模型验证标签助手不会通过 ViewComponent 中的 unobtrusiveJS 出现
我为位于 ViewComponent 内的一组复选框创建了一个自定义验证属性。在我将它移动到 ViewComponent 之前,不显眼的验证消息通过 asp-validation-for 完美地工作,但现在消息没有出现在那里。
与此同时,我正在收集服务器端验证错误并将它们传递回视图,并且按预期工作:所以我收到了我通过自定义属性发出的错误消息,它只是没有显示中的消息。
这是代码(我正在尽可能地简化它,如果您需要更多信息,请告诉我。如果我遗漏了什么,我深表歉意。):
控制器:
public IActionResult Enrollment(Enrollmentviewmodel enrollmentVM)
{
return View("~/Enrollment.cshtml",enrollmentVM);
}
public Enrollmentviewmodel SetModelListItems(Enrollmentviewmodel enrollmentVM)
{
if (enrollmentVM.Preferences == null)
{
var preferencesList = preferences.GetAll().ToList();
enrollmentVM.Preferences = preferences.Select(x => new SelectListItem
{
Text = x.PreferencesName,Value = x.PreferenceseId.ToString()
}).ToList();
return enrollmentVM;
}
public async Task<IViewComponentResult> InvokeAsync(Enrollmentviewmodel enrollmentVM)
{
enrollmentVM = SetModelListItems(enrollmentVM);
return new ViewViewComponentResult()
{
ViewData = new ViewDataDictionary<Enrollmentviewmodel>(ViewData,enrollmentVM)
};
主视图:
@model Enrollmentviewmodel;
@{
Layout = "_Layout.cshtml";
}
<button type="submit" id="EnrollForm" form="EnrollForm">
<span>Save</span>
</button>
<div>
@await Component.InvokeAsync("EnrollClient",new { enrollmentVM = @Model });
</div>
@section Scripts
{
@if (Model.HasErrors)
{
@foreach (string errorMessage in Model.SubmitErrors)
{
<script type="text/javascript">
toastr["error"]("@errorMessage");
</script>
}
}
视图组件:
@model Enrollmentviewmodel
@using (Html.BeginForm("EnrollClient","Enrollment",FormMethod.Post,new { enctype = "multipart/form-data",id = "EnrollForm" }))
{
<fieldset>
<legend>Preferences (select all that apply)</legend>
@for (var i = 0; i < Model.Preferences.Count(); i++)
{
<div>
<input type="checkBox" asp-for="@Model.Preferences[i].Selected">
<label asp-for="@Model.Preferences[i].Selected">@Model.Races[i].Text</label>
<input type="hidden" asp-for="@Model.Preferences[i].Value" />
<input type="hidden" asp-for="@Model.Preferences[i].Text" />
</div>
}
<span asp-validation-for="Preferences" class="text-danger"></span>
</fieldset>
POST 方法:
public IActionResult EnrollClient(Enrollmentviewmodel viewmodel)
{
try
{
if (!ModelState.IsValid)
{
viewmodel = SetModelListItems(viewmodel);
viewmodel.HasErrors = true;
viewmodel.SubmitErrors = ModelState.Values
.SelectMany(state => state.Errors)
.Select(error => error.ErrorMessage);
return View("~/Enrollment.cshtml",viewmodel);
}
SaveForm();
}
//....
}
带有属性的视图模型:
public class Enrollmentviewmodel
{
[ListItemSelected(ErrorMessage = "Please select at least one Preference option.")]
public List<SelectListItem> Preferences { get; set; }
}
public class ListItemSelectedAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value != null)
{
if ((value as List<SelectListItem>).Count(x => x.Selected) == 0)
return new ValidationResult(ErrorMessage);
}
return ValidationResult.Success;
}
}
我觉得这是很多代码,但希望其中大部分是解释我的问题所必需的......我把它删减了很多。 jquery、验证和不显眼的脚本在 _Layout.cshtml 中。非常感谢!
编辑:
我在 ViewComponent 和 Main View 文件中放置了一个断点,并且在两者的 Locals 选项卡中,ViewContext 显示 ModelState 无效,并且 ValidationMessageElement = "span"!我想这不是它应该的样子??我找到了一篇推荐添加 ViewContext.FormContext = new FormContext(); 的帖子。在顶部,但无论有没有它,FormContext 项都是相同的。
解决方法
我测试了您的代码,但未触发提交按钮。另外,当您在 Html.BeginForm
中设置它时,我没有看到Enroll
操作
@using (Html.BeginForm("Enroll","Enrollment",FormMethod.Post,new { enctype = "multipart/form-data",id = "EnrollForm" }))
我根据您的代码制作了一个示例,这似乎按您的预期工作。
主视图 (Enrollment.cshtml)
@model EnrollmentViewModel
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Enrollment</h1>
<div>
@await Component.InvokeAsync("EnrollClient",new { enrollmentVM = @Model })
</div>
ViewComponent(Default.cshtml):
@model EnrollmentViewModel
@{
var x = Model;
}
@using (Html.BeginForm("Enroll",id = "EnrollForm" }))
{
<fieldset>
<legend>Preferences (select all that apply)</legend>
@for (var i = 0; i < Model.Preferences.Count(); i++)
{
<div>
<input type="checkbox" asp-for="@Model.Preferences[i].Selected">
<label>@Model.Preferences[i].Text</label>
<input type="hidden" asp-for="@Model.Preferences[i].Value" />
<input type="hidden" asp-for="@Model.Preferences[i].Text" />
</div>
}
<button type="submit" id="EnrollForm" form="EnrollForm">
<span>Save</span>
</button>
<span asp-validation-for="Preferences" class="text-danger"></span>
</fieldset>
}
注册ClientViewComponent.cs
public class EnrollClientViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(EnrollmentViewModel enrollmentVM)
{
enrollmentVM = SetModelListItems(enrollmentVM);
return new ViewViewComponentResult()
{
ViewData = new ViewDataDictionary<EnrollmentViewModel>(ViewData,enrollmentVM)
};
}
public EnrollmentViewModel SetModelListItems(EnrollmentViewModel enrollmentVM)
{
enrollmentVM.Preferences = new List<SelectListItem>
{
new SelectListItem{ Text = "A",Value = "1"},new SelectListItem{ Text = "B",Value = "2"},new SelectListItem{ Text = "C",Value = "3"},};
return enrollmentVM;
}
}
控制器:
public class EnrollmentController : Controller
{
public IActionResult Enrollment(EnrollmentViewModel enrollmentVM)
{
return View("Enrollment",enrollmentVM);
}
[HttpPost]
public IActionResult Enroll(EnrollmentViewModel enrollmentVM)
{
if (!ModelState.IsValid)
{
return View("Enrollment",enrollmentVM);
}
else
{
//SaveForm
return View("Enrollment",enrollmentVM);
}
}
}
项目结构:
结果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。