对EditorTemplate ASP MVC 5

时间:2018-08-28 11:52:16

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

我有以下型号

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的{​​{1}}(在其他视图中重复使用)

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

单击模板中的按钮时,我将进行ajax调用,以将模板中输入的值发布到执行一些服务器端计算的控制器方法。如果输入的值无效,则会收到@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> 错误并返回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<string, object>

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

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

1 个答案:

答案 0 :(得分:1)

您需要做的第一件事是删除该ValidationMessageForBootstrap()扩展方法,并使用内置的@Html.ValidationMessageFor()来正确生成客户端和服务器端验证消息的占位符。如果检查它生成的<span>,它具有一个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 });

并将其分配给Errors的{​​{1}}属性。

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

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

propertyName

为避免不必要的ajax调用,还应该验证$('#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调用。有关仅验证模板中的表单控件的示例,请参见MVC Force jQuery validation on group of elements