这里有两个问题,都是相关的。
第一个问题涉及在.NET MVC中使用[Required] bool?
和jQuery Validate,其中不阻止表单在没有值的情况下发布,当用户将切换到中间null
位置时也不会显示警告消息(True /空/ FALSE)。
第二个问题涉及使用[BooleanRequired] bool
以及在.NET MVC中使用CheckBoxFor和jQuery Validate,因为在某些情况下CheckBox实际上会消失。例如在Chrome中,如果您在不勾选条款复选框的情况下发布表单,则删除:: before状态,因此CheckBox消失,但在IE11中不会发生这种情况,但是在显示警告后取消勾选CheckBox会导致CheckBox消失。
以下代码的代码如下:
HomeController.cs
public ActionResult Test()
{
return View();
}
[HttpPost]
public ActionResult Test(Test test)
{
if (ModelState.IsValid)
{
//return Redirect("/thank-you");
}
return View(test);
}
Test.cshtml
<section class="content container">
<article class="content content__full">
@Html.Partial("_TestForm")
</article>
</section>
_TestForm.cshtml
@using WebAppliation1.Helpers
@model WebAppliation1.Models.Test
@using (Html.BeginForm("Test", "Home", FormMethod.Post, new { id = "TestForm", @class = "test-form" }))
{
@Html.ValidationSummary()
<div id="QuestionDiv">
<label>Are you a badger?</label>
@Html.HiddenForExt(model => model.Question, new Dictionary<string, object> { { "required", "required" } })
</div>
<footer>
@Html.CheckBoxFor(model => model.Terms, new Dictionary<string, object> { { "required", "required" } })
@Html.LabelFor(model => model.Terms)
<a href="/terms-and-conditions" target='_Blank'>Terms and Conditions</a>
@Html.ValidationMessageFor(model => model.Terms)
<input type="submit" value="Submit" class="btn" />
</footer>
}
@Scripts.Render("~/Scripts/jqueryNouisliderAll")
@Scripts.Render("~/Scripts/test")
test.js
$(document).ready(function () {
var question = $("#Question").val();
question = question === "" ? "1" : question === "True" ? "0" : "2";
$("#QuestionDiv").toggle({
selectorName: "QuestionDiv",
displaySelectedValue: false,
start: question
});
$("#QuestionDiv").on("change", function () {
question = this.value;
question = question === "1" ? null : question === "0" ? "True" : "False";
$("#Question").val(question);
});
});
$.validator.messages.required = function (param, input) {
return $(input).data("val-required");
}
$.validator.addMethod("notEqual", function (value, element, param) {
return this.optional(element) || value !== param;
}, "Please specify a different (non-default) value");
$("#TestForm").validate({
rules: {
Question: {
notEqual: null
},
//Question: {
// //minlength: 4,
// //required: true
// required: function(element) {//
// return $("#QuestionDiv").value !== 1;
// }
//},
Terms: {
required: true
}
},
messages: {
Terms: {
required: "You must accept the terms and conditions"
},
Question: {
minlength: "Please select either Yes or No",
required: "The Question field is required"
}
},
errorPlacement: function (error, element) {
var text = error.text();
if (text.indexOf("required") !== -1) {
element.attr("placeholder", error.text());
} else {
error.insertAfter(element);
}
},
highlight: function (element) {
if ($(element).is("select")) {
$(element.form).find("select[id=" + element.id + "]").parent().find("span").addClass("error").removeClass("valid");
} else {
$(element).addClass("error").removeClass("valid");
}
},
unhighlight: function (element) {
if ($(element).is("select")) {
$(element.form).find("select[id=" + element.id + "]").parent().find("span").addClass("valid").removeClass("error");
} else {
$(element).addClass("valid").removeClass("error");
var label = $("label[for='" + element.id + "']").text();
$(element).prop("placeholder", label);
}
},
focusInvalid: true
});
(function ($) {
var pluginName = "toggle";
function plugin(element, options) {
var toggle = null;
var leftLabel = null;
var rightLabel = null;
var $el = $(element);
var $toggle = null;
var $leftLabel = null;
var $rightLabel = null;
options = $.extend({}, $.fn[pluginName].defaults, options);
function render() {
$el.append("<span class='toggle-slider__option toggle-slider__option-left'>" + options.leftLabelText + "</span>");
$el.append("<div class='toggle-slider'></div>");
$el.append("<span class='toggle-slider__option toggle-slider__option-right'>" + options.rightLabelText + "</span>");
var type = "hidden";
if (options.displaySelectedValue) {
type = "text";
}
$el.append("<input id='" + options.selectorName + "' name='" + options.selectorName + "' class='toggle-slider-display' type='" + type + "' value='" + options.start + "'></input>");
toggle = $el.children(".toggle-slider");
leftLabel = $el.children(".toggle-slider__option-left");
rightLabel = $el.children(".toggle-slider__option-right");
$toggle = $(toggle);
$leftLabel = $(leftLabel);
$rightLabel = $(rightLabel);
}
function configure() {
$toggle.noUiSlider({
range: {
'min': options.minVal,
'max': options.maxVal
},
format: options.format,
start: options.start
});
}
function toggleVal(value) {
$("#" + options.selectorName).val(value);
$leftLabel.removeClass("left");
$rightLabel.removeClass("right");
$toggle.removeClass("left");
$toggle.removeClass("right");
$toggle.removeClass("off");
switch (value) {
case "0":
$leftLabel.addClass("left");
$toggle.addClass("left");
break;
case "2":
$rightLabel.addClass("right");
$toggle.addClass("right");
break;
default:
$toggle.addClass("off");
}
}
function bind() {
$leftLabel.click(function () {
$toggle.val(0);
});
$rightLabel.click(function () {
$toggle.val(2);
});
$toggle.Link().to(toggleVal);
}
function init() {
render();
configure();
bind();
}
function destroy() {
$el.each(function () {
var $el = $(this);
hook("onDestroy");
$el.removeData("plugin_" + pluginName);
});
}
init();
return {
destroy: destroy
};
}
$.fn[pluginName] = function (options) {
if (typeof options === "object" || !options) {
return this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new plugin(this, options));
}
});
}
};
$.fn[pluginName].defaults = {
onInit: function () { },
onDestroy: function () { },
step: 1,
minVal: [0, 1, 2],
maxVal: 2,
displaySelectedValue: true,
start: 1,
selectorName: pluginName + "Selector",
format: wNumb({
decimals: 0
}),
leftLabelText: "Yes",
rightLabelText: "No"
};
}($));
InputExtender.cs
public static MvcHtmlString HiddenForExt<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes = null, bool readOnly = false)
{
if (htmlAttributes == null)
{
htmlAttributes = new Dictionary<string, object>();
}
var modelMetadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
if (modelMetadata != null) htmlAttributes.Add("id", modelMetadata.PropertyName);
var memberExpression = expression.Body as MemberExpression;
var stringLengthAttribute = memberExpression?.Member.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault() as StringLengthAttribute;
if (stringLengthAttribute != null)
{
if (htmlAttributes.ContainsKey("maxlength") == false)
{
htmlAttributes.Add("maxlength", stringLengthAttribute.MaximumLength);
}
}
return html.HiddenFor(expression, htmlAttributes);
}
test.cs中
public class Test
{
[Required(ErrorMessage = "Are you a badger? Requires a Yes or No")]
[Display(Name = "Are you a badger?")]
public bool? Question { get; set; }
[BooleanRequired(ErrorMessage = "You must accept the terms and conditions.")]
[Display(Name = "I agree with the ")]
public bool Terms { get; set; }
}
如果它有助于我使用jquery-2.1.4.js,jquery.validate-1.17.0.js和jquery.validate.unobtrusive-3.2.11.js。
我希望有人能够对我可能做错了什么或者如何为这些问题提供解决方法有所了解。
隐藏字段未被验证的问题是因为默认情况下它们被忽略,您必须指定是否要验证要使用的隐藏字段。要验证所有隐藏字段使用ignore: ""
,在我的情况下我使用ignore: ":hidden:not(#Question)"
。之前使用的errorPlacement导致CheckBox消失。
以下是修正后的test.js
,它纠正了上述所有问题:
$(document).ready(function () {
var question = $("#Question").val();
question = question === "" ? "1" : question === "True" ? "0" : "2";
$("#QuestionDiv").toggle({
selectorName: "QuestionDiv",
displaySelectedValue: false,
start: question
});
$("#QuestionDiv").on("change", function () {
question = this.value;
if (question === "1") {
$("label[for*='Question']").html("Are you a badger? requires either Yes or No");
} else {
$("label[for*='Question']").html("Are you a badger?");
}
question = question === "1" ? null : question === "0" ? "True" : "False";
$("#Question").val(question);
});
});
$.validator.messages.required = function (param, input) {
return $(input).data("val-required");
}
$("#TestForm").validate({
ignore: ":hidden:not(#Question)",
rules: {
Question: {
required: function () {
var questionDiv = $("#QuestionDiv").val();
if (questionDiv === "1") {
$("label[for*='Question']").html("Are you a badger? requires either Yes or No");
} else {
$("label[for*='Question']").html("Are you a badger?");
}
return questionDiv === "1" ? true : false;
}
},
Terms: {
required: true
}
},
messages: {
Terms: {
required: "You must accept the terms and conditions"
},
Question: {
required: "The Question field is required"
}
},
errorPlacement: function (error, element) {
var text = error.text();
if (text.indexOf("required") !== -1) {
element.attr("placeholder", error.text());
} else {
if ($(element).is(':checkbox')) {
error.insertAfter(element.closest("footer"));
} else {
error.insertAfter(element);
}
}
},
highlight: function (element) {
if ($(element).is("select")) {
$(element.form).find("select[id=" + element.id + "]").parent().find("span").addClass("error").removeClass("valid");
} else {
$(element).addClass("error").removeClass("valid");
}
},
unhighlight: function (element) {
if ($(element).is("select")) {
$(element.form).find("select[id=" + element.id + "]").parent().find("span").addClass("valid").removeClass("error");
} else {
$(element).addClass("valid").removeClass("error");
var label = $("label[for='" + element.id + "']").text();
$(element).prop("placeholder", label);
}
},
focusInvalid: false
});
(function ($) {
var pluginName = "toggle";
function plugin(element, options) {
var toggle = null;
var leftLabel = null;
var rightLabel = null;
var $el = $(element);
var $toggle = null;
var $leftLabel = null;
var $rightLabel = null;
options = $.extend({}, $.fn[pluginName].defaults, options);
function render() {
$el.append("<span class='toggle-slider__option toggle-slider__option-left'>" + options.leftLabelText + "</span>");
$el.append("<div class='toggle-slider'></div>");
$el.append("<span class='toggle-slider__option toggle-slider__option-right'>" + options.rightLabelText + "</span>");
var type = "hidden";
if (options.displaySelectedValue) {
type = "text";
}
$el.append("<input id='" + options.selectorName + "' name='" + options.selectorName + "' class='toggle-slider-display' type='" + type + "' value='" + options.start + "'></input>");
toggle = $el.children(".toggle-slider");
leftLabel = $el.children(".toggle-slider__option-left");
rightLabel = $el.children(".toggle-slider__option-right");
$toggle = $(toggle);
$leftLabel = $(leftLabel);
$rightLabel = $(rightLabel);
}
function configure() {
$toggle.noUiSlider({
range: {
'min': options.minVal,
'max': options.maxVal
},
format: options.format,
start: options.start
});
}
function toggleVal(value) {
$("#" + options.selectorName).val(value);
$leftLabel.removeClass("left");
$rightLabel.removeClass("right");
$toggle.removeClass("left");
$toggle.removeClass("right");
$toggle.removeClass("off");
switch (value) {
case "0":
$leftLabel.addClass("left");
$toggle.addClass("left");
break;
case "2":
$rightLabel.addClass("right");
$toggle.addClass("right");
break;
default:
$toggle.addClass("off");
}
}
function bind() {
$leftLabel.click(function () {
$toggle.val(0);
});
$rightLabel.click(function () {
$toggle.val(2);
});
$toggle.Link().to(toggleVal);
}
function init() {
render();
configure();
bind();
}
function destroy() {
$el.each(function () {
var $el = $(this);
hook("onDestroy");
$el.removeData("plugin_" + pluginName);
});
}
init();
return {
destroy: destroy
};
}
$.fn[pluginName] = function (options) {
if (typeof options === "object" || !options) {
return this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new plugin(this, options));
}
});
}
};
$.fn[pluginName].defaults = {
onInit: function () { },
onDestroy: function () { },
step: 1,
minVal: [0, 1, 2],
maxVal: 2,
displaySelectedValue: true,
start: 1,
selectorName: pluginName + "Selector",
format: wNumb({
decimals: 0
}),
leftLabelText: "Yes",
rightLabelText: "No"
};
}($));
我还修改了<label>Are you a badger?</label>
到@Html.LabelFor(model => model.Question)
以正确地定位jQuery $("label[for*='Question']")
中的标签,并使用其他代码来控制标签文本,当使用表单验证或用户交互时,因为使用@Html.ValidationMessageFor(model => model.Question)
甚至会隐藏@Html.HiddenForExt(model => model.Question, new Dictionary<string, object> { { "required", "required" } })
。