微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自定义服务器端模型验证标签助手不会通过 ViewComponent 中的 unobtrusiveJS 出现

如何解决自定义服务器端模型验证标签助手不会通过 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);
        }
    }
}

项目结构:

enter image description here

结果:

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?