我在做什么:我有3个组合框。前2个框中的选择决定了第3个框中的列表。每当在前两个框中的任何一个框中进行选择时,我运行一些jQuery,它进行$ .ajax调用以获取第3个框的列表。第3个框是我的“项目描述”框。
问题: jquery ajax调用有效。当我在前两个框中选择值时,项目描述将被加载到第3个框中。但是,当我尝试提交表单时,ModelState.IsValid = false和ModelState错误消息显示“项目描述是必需的。”
这来自我的模型的元数据:
[Required(ErrorMessage = "Item Description is required.")]
public int ItemDescriptionID { get; set; }
我不希望用户在不选择说明的情况下提交表单。我可以在提交后进行验证,但我希望MVC能够进行验证。
这是我正在使用的JavaScript ......
function getModels() {
catId = $('#ItemModel_ItemCategoryID').val();
manuId = $('#ItemModel_ItemManufacturerID').val();
// remove all of the current options from the list
$('#ItemDescriptionID').empty();
// send request for model list based on category and manufacturer
var jqxhr = $.ajax({
url: '/Threshold/GetModels',
type: 'POST',
data: '{ CategoryID: ' + catId.toString() + ', ManufacturerID: ' + manuId.toString() + ' }',
contentType: 'application/json',
dataType: 'json',
cache: false,
async: true
});
// received list of models...
jqxhr.done(function (data) {
if (data == null) return;
try {
var ddl = $('#ItemDescriptionID');
// add each item to DDL
$.each(data, function (index, value) {
ddl.append($('<option/>', {value: data[index].ItemDescriptionID}).html(data[index].ItemDescription))
});
}
catch (result) {
alert("Done, but with errors! " + result.responseText);
}
});
// failed to retrieve data
jqxhr.error(function (result) {
alert("Error! Failed to retrieve models! " + result.responseText);
});
}
那么我做错了什么?如果我删除必需的元数据标记,表单将提交。此外,在表单提交后,我可以从下拉列表中获取ID,一切正常。问题在于模型状态/验证。
编辑:
这是描述框的剃刀......
@Html.DropDownListFor(m => m.ItemDescriptionID, new SelectList(new List<SelectListItem>()) )
@Html.ValidationMessageFor(m => m.ItemDescriptionID)
答案 0 :(得分:1)
如果我正确理解您的问题,您认为问题是即使用户未从您的下拉列表中选择任何有效内容,他们仍然可以发布到服务器。当用户未选择任何ModelState.IsValid为false并且您收到正确的错误消息时,模型似乎正确验证。但是,如果尚未进行选择,您希望完全避免发布数据。
这里的问题是ModelState和所有MVC验证实际上是在服务器端完成的。因此,为了让您的应用程序根据您的模型的数据注释检测到用户的选择无效,确实需要表单提交。
为了阻止用户发布,您想要的是客户端验证,这不是MVC模型验证的一部分,但MVC 4已经内置了对它的支持。
为了使用内置的MVC 4 jQuery验证启用客户端验证,请执行以下操作。
确保“Unobtrusive JavaScript”(将输出所需的HTML属性)和“客户端验证”(将连接javascript)。
在web.config中(针对整个网站)
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
或者在代码中 - global.asax.cs,视图或控制器,具体取决于您想要的范围
HtmlHelper.ClientValidationEnabled = true;
HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
MVC 4已经准备了一个捆绑包,包括jQuery验证和不显眼的验证脚本。这必须在jQuery包之后添加。
@Scripts.Render("~/bundles/jqueryval")
即使您启用了客户端验证,也必须在执行任何操作之前对发布的数据执行服务器端验证。无论用户提交的数据是有效还是 无效 ,您的ActionMethod仍将执行...因此,您需要先检查IsValid,然后再对已提交的数据执行操作
[HttpPost]
public ActionResult ActionMethodName(ModelClass modelParameterName)
{
//exit directly on invalid data
if(!ModelState.IsValid) return View(modelParameterName);
//okay to save data etc...
...
...
//return whatever makes sense for your scenario
return View(modelParameterName);
}
您也可以手动使用jQuery验证或其他第三方javascript验证库。
自定义javascript表单验证也是一个选项 - 从表单的提交事件中调用的函数返回false。
HTML5支持客户端验证属性(在您的情况下为“必需”),但并非所有浏览器都实现它。
如果您在不使用MVC 4不显眼的脚本的情况下自行执行验证,则应该关闭内置功能以避免冲突并减小返回HTML的大小。
<appSettings>
<add key="ClientValidationEnabled" value="false"/>
<add key="UnobtrusiveJavaScriptEnabled" value="false"/>
</appSettings>
或者在代码中,您可以控制要应用的范围。
HtmlHelper.ClientValidationEnabled = false;
HtmlHelper.UnobtrusiveJavaScriptEnabled = false;