我有以下型号
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()
函数中的代码未更新消息。
如何在视图中找到正确的元素以更新错误消息?
答案 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