【问题标题】:Custom validation for a EditorTemplate ASP MVC 5EditorTemplate ASP MVC 5 的自定义验证
【发布时间】:2019-02-03 01:09:24
【问题描述】:

我有以下型号

public class A
{
    public string Ecuation { get; set; }
    ...
    public B B { get; set; }
}
public class B // validation attributes omitted
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public int Number3 { get; set; }
}

还有一个EditorTemplate 用于B(在其他视图中重复使用)

@model B
<div id="EcuationGenerator">
    @Html.EditorFor(x => x.Number1)
    @Html.ValidationMessageForBootstrap(x => x.Number1)
    .... // ditto for other properties
    <button id="sendEcuation">Fill Ecuation</button>
</div>

<script>
    $('#sentEcuation').on('click', function (e) {
        e.preventDefault();
        $.ajax({
            cache: false,
            type: "POST",
            url: '@Url.Action("ValidateB")',
            data: $('#EcuationGenerator :input').serialize(),
            dataType: "json"
        })
        .done(function (data) {
            if (data.Valid) {
                // working here about how can i get the 'Ecuation' to fill the input
                return;
            }
            $.each(data.Errors, function (key, value) {
                // The following is not working to update the error messages
                if (value != null) {
                    key = key.replace('.', '\\.');
                    $(":input[name='" + key + "']").addClass("is-invalid");
                    key = key.replace('[', '\\['); key = key.replace(']', '\\]');
                    $("#Err_" + key).text(value[value.length - 1].ErrorMessage);
                }
            });
        })
        .fail(function (xhr) {
            alert(xhr.responseText);
            alert("Critical Error!. Failed to call the server.");
        });
    });
</script>

ValidationMessageForBootstrap() 扩展方法在哪里

public static MvcHtmlString ValidationMessageForBootstrap<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null) 
{ 
    if (expression == null) { throw new ArgumentNullException("Campo vacío"); } 
    string result = string.Empty; 
    try 
    { 
        Func<TModel, TValue> deleg = expression.Compile(); 
        result = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression)); 
    }
    catch { } 
    var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); 
    attributes["class"] += " invalid-feedback"; 
    attributes["id"] += "Err_" + result; 
    TagBuilder generador = new TagBuilder("div"); 
    generador.MergeAttributes(new RouteValueDictionary(attributes)); 
    return new MvcHtmlString(generador.ToString()); 
}

主视图是

@model A
....
@Html.EditorFor(x => x.Ecuation, new {htmlAttributes = new { @readonly = "readonly" }})
<button class="btn btn-outline-dark rounded-right" data-keyboard="false" data-toggle="modal" data-target="#modal" id="abrirConexionado" type="button">Fill Ecuation!</i></button>

<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-body">
                @Html.EditorFor(m => m.B })
            </div>
        </div>
    </div>
</div>

当我单击模板中的按钮时,我会进行 ajax 调用以将模板中的输入值发布到执行某些服务器端计算的控制器方法。如果输入的值无效,我会收到ModelState 错误,然后在JsonResult 中返回,然后我想用它来更新我的ValidationMessageForBootstrap() 方法生成的元素中的消息。

控制器方法是

public JsonResult ValidateB(B b)
{
    var valid = TryUpdateModel(b)
    if(valid)
    {
        error = false;
        //More Logic
    }
    return Json(new 
    {
        EcuationResult = //logic,
        Valid = valid,
        Errors = getErrorsForModel()
    });
}

getErrorsForModel() 方法返回带有 ModelState 错误的 IDictionary&lt;string, object&gt;

我的问题是JsonResult 中返回的属性名称只是Number1 等,不包括视图中生成的全名(即B.Number1)和我在ajax 中的代码.done() 函数没有更新消息。

如何在视图中找到正确的元素以更新错误消息?

【问题讨论】:

  • 我假设您的意思是B.Number1(不是A)。但是,如果您将错误返回为key=Number1, value="some error message",那么您只需要通过根据. 字符拆分名称来更新@Html.ValidationMessageFor() 生成的任何占位符
  • 您好,谢谢您的回答,您的意思是直接用javascript做吗?
  • 如果您返回JsonResult,您必须使用javascript 更新消息。但我只是假设这是你想要做的,因为你的问题没有说明,也没有显示任何与之相关的代码
  • 这正是我想要做的,我的问题是使代码可重用,我不知道我是否可以从控制器访问 B 名称,或者必须为每个查看谁实现了B模板,我解释一下吗?
  • 除非您在问题中解释您想要做什么,并包含相关代码(包括您尝试在 ajax 调用中更新消息的代码),否则我们无法为您提供帮助

标签: c# ajax asp.net-mvc razor asp.net-mvc-5


【解决方案1】:

您需要做的第一件事是删除 ValidationMessageForBootstrap() 扩展方法并使用内置的 @Html.ValidationMessageFor() 正确生成客户端和服务器端验证消息的占位符。如果您检查它生成的&lt;span&gt;,它有一个data-valmsg-for 属性,其值是属性的全名,您可以使用它来查找与属性关联的消息占位符。

接下来从模板中删除脚本 - 脚本进入主视图或其布局,而不是部分视图。

你的EditorTemplate应该是

@model B
<div id="EcuationGenerator">
    @Html.EditorFor(x => x.Number1)
    @Html.ValidationMessageFor(m => m.x.Number1) // add
    ... // ditto for other properties
    <button type="button" id="sendEcuation">Fill Ecuation</button> // add type="button"
</div>

然后更改服务器方法中的代码以获取验证消息的集合使用

var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0)
    .Select(k => new { propertyName = k, errorMessage = ModelState[k].Errors[0].ErrorMessage });

并将其分配给您的JsonResultErrors 属性。

然后,您可以使用 javascript .split()pop().join() 方法确定属性名称的“前缀”,并附加错误集合中返回的 propertyName 以查找关联的输入及其消息占位符,然后更新这些元素的消息文本和类名

然后脚本(在主视图中)将是

$('#sentEcuation').click(function() {
    // Determine the prefix of the property names
    var fullName = $('#EcuationGenerator').find('input').first().attr('name'); // returns "B.Number1"
    var parts = fullName.split('.'); // returns [ "B", "Number1" ]
    parts.pop(); // returns [ "B" ]
    var prefix = parts.join('.') + '.'; returns "B."
    $.ajax({
        ....
    })
    .done(function (data) {
        if (data.Valid) {
            // Update input with the result
            $('#Ecuation').val(data.EcuationResult);
            return;
        }
        $.each(data.Errors, function (index, item) {
            var fullName = prefix + item.propertyName;
            // Get the validation message placeholder
            var element = $('[data-valmsg-for="' + fullName + '"]');
            // Update message
            element.append($('<span></span>').text(item.errorMessage));
            // Update class names
            element.removeClass('field-validation-valid').addClass('field-validation-error');
            $('[name="' + fullName + '"]').removeClass('valid').addClass('input-validation-error');
        });
    })
    .fail(function (xhr) {
        ....
    });
});

为避免不必要的 ajax 调用,您还应该验证 EditorTemplate 中的输入,如果无效,则取消 ajax 调用。有关仅验证模板中的表单控件的示例,请参阅 MVC Force jQuery validation on group of elements

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 2016-12-12
    • 1970-01-01
    • 2016-10-19
    • 2012-03-03
    • 1970-01-01
    相关资源
    最近更新 更多