简体   繁体   English

自定义验证EditorTemplate ASP MVC 5

[英]Custom validation for a EditorTemplate ASP MVC 5

I have the following models 我有以下型号

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

and an EditorTemplate for B (its reused in other views) BEditorTemplate (在其他视图中重用)

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

Where the ValidationMessageForBootstrap() extension method is 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()); 
}

and the main view is 主要的观点是

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

When I click the button in the template, I make an ajax call to post the value of the inputs in the template to a controller method that perform some server side calculations. 当我单击模板中的按钮时,我进行了ajax调用,以将模板中的输入值发布到执行一些服务器端计算的控制器方法。 If the value of the inputs are not valid I get the ModelState errors and return then in a JsonResult , which I then want to use to update the message in the element generated by my ValidationMessageForBootstrap() methods. 如果输入值无效,则会收到ModelState错误并返回JsonResult ,然后将其用于更新ValidationMessageForBootstrap()方法生成的元素中的消息。

The controller method is 控制器方法是

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

The getErrorsForModel() method returns a IDictionary<string, object> with the ModelState errors. getErrorsForModel()方法返回IDictionary<string, object> ModelState错误的IDictionary<string, object>

My problem is that the names of the properties returned in the JsonResult are just Number1 etc and do not include the full name (ie B.Number1 ) which is generated in the view, and my code in the ajax .done() function is not updataing the messages. 我的问题是,在JsonResult中返回的属性的名称只是Number1等,并且不包括视图中生成的全名(即B.Number1 ),而我在ajax .done()函数中的代码却没有更新消息。

How can I find the correct elements in the view in order to update the error messages? 如何在视图中找到正确的元素以更新错误消息?

The first thing you need to do is delete that ValidationMessageForBootstrap() extension method and use the inbuilt @Html.ValidationMessageFor() which correctly generates the placeholder for client and server side validation messages. 您需要做的第一件事是删除ValidationMessageForBootstrap()扩展方法,并使用内置的@Html.ValidationMessageFor()正确生成客户端和服务器端验证消息的占位符。 If you inspect the <span> that it generates, it has a data-valmsg-for attribute whose value is the full name of the property which you can use to find the the message placeholder associated with a property. 如果检查它生成的<span> ,它具有data-valmsg-for属性,其值是属性的全名,可用于查找与该属性关联的消息占位符。

Next delete the scripts from your template - scripts go in the main view or its layout, not in partial views. 接下来,从模板中删除脚本-脚本进入主视图或其布局,而不是局部视图。

Your EditorTemplate should be 您的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>

Then change the code in the server method to get a collection of the validation messages using 然后在server方法中更改代码以使用获取验证消息的集合

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

and assign that to the Errors property of your JsonResult . 并将其分配给JsonResultErrors属性。

You can then determine the 'prefix' of the property name using the javascript .split() , pop() and .join() methods, and append the propertyName returned in the errors collection to find the associated input and its message placeholder, then update the message text and class names of those elements 然后,您可以使用javascript .split()pop().join()方法确定属性名称的“前缀”,然后附加在错误集合中返回的propertyName ,以找到关联的输入及其消息占位符,然后更新这些元素的消息文本和类名称

And then the script (in the main view) will be 然后脚本(在主视图中)将是

$('#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) {
        ....
    });
});

To avoid unnecessary ajax calls, you should also validate the inputs in your EditorTemplate and if not valid, then cancel the ajax call. 为了避免不必要的ajax调用,还应该验证EditorTemplate的输入,如果无效,则取消ajax调用。 For an example of validating just the form controls in your template, refer MVC Force jQuery validation on group of elements 有关仅验证模板中的表单控件的示例,请参阅关于元素组的MVC Force jQuery验证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM