У меня есть два входа, которые мне нужно проверить друг против друга. Они минимальные и максимальные. Вот часть моего представления, определяющая их.
<div class="form-group">
<label asp-for="MinTubes" class="control-label"></label>
<input asp-for="MinTubes" class="form-control" />
<span asp-validation-for="MinTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MaxTubes" class="control-label"></label>
<input asp-for="MaxTubes" class="form-control" />
<span asp-validation-for="MaxTubes" class="text-danger"></span>
</div>
А вот свойства, которым они сопоставлены:
[Display(Name = "Min Tubes")]
[MinToValidation("MaxTubes")]
public int MinTubes { get; set; }
[Display(Name = "Max Tubes")]
[MaxToValidation("MinTubes")]
public int MaxTubes { get; set; }
В результате <input type='number'>
элементов с метками и проверкойmessages.
Я создал два пользовательских атрибута проверки для работы с ними. Я опубликую только класс MaxToValidationAttribute
, так как другой класс функционально идентичен.
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;
using System.ComponentModel.DataAnnotations;
namespace CCM_Util.CustomAttributes
{
public class MaxToValidationAttribute : ValidationAttribute, IClientModelValidator
{
public MaxToValidationAttribute(string min)
: base("{0} must be greater than or equal to {1}")
{
Min = min;
}
public string Min { get; set; }
public string FormatErrorMessage(string name, string minName)
{
return string.Format(ErrorMessageString, name, minName);
}
protected override ValidationResult
IsValid(object firstValue, ValidationContext validationContext)
{
var firstComparable = firstValue as IComparable;
var secondComparable = GetSecondComparable(validationContext);
if (firstComparable != null && secondComparable != null)
{
if (firstComparable.CompareTo(secondComparable) < 0)
{
object obj = validationContext.ObjectInstance;
var thing = obj.GetType().GetProperty(Min);
var displayName = (DisplayAttribute)Attribute.GetCustomAttribute(thing, typeof(DisplayAttribute));
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName, displayName.GetName()));
}
}
return ValidationResult.Success;
}
protected IComparable GetSecondComparable(
ValidationContext validationContext)
{
var propertyInfo = validationContext
.ObjectType
.GetProperty(Min);
if (propertyInfo != null)
{
var secondValue = propertyInfo.GetValue(
validationContext.ObjectInstance, null);
return secondValue as IComparable;
}
return null;
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val-min", Min);
context.Attributes.Add("data-val-ismax", "true");
}
}
}
Затем, в Default.js, у меня есть следующая функция, выполняемая как часть моей функции document.ready
.
function minMaxValidate() {
$("input[data-val-ismin='true']").each(function (i, ele) {
$(ele).change(function () {
var maxName = $(this).attr("data-val-max");
var minName = $(this).attr("name");
var minValue = parseFloat($(this).val());
var max = $("input[data-val-ismax='true'][name='" + maxName + "']");
var maxValue = max.val();
if (maxValue == "") { return }
maxValue = parseFloat(maxValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(minName + " must not be greater than " + maxName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
$("input[data-val-ismax='true']").each(function (i, ele) {
$(ele).change(function () {
var minName = $(this).attr("data-val-min");
var maxName = $(this).attr("name");
var maxValue = parseFloat($(this).val());
var min = $("input[data-val-ismin='true'][name='" + minName + "']");
var minValue = min.val();
if (minValue == "") { return }
minValue = parseFloat(minValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(maxName + " must not be less than " + minName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
}
Функции makeError
и makeValid
по сути просто меняют класс validationMessage
на field-validation-error
и field-validation-valid
соответственно и управляют обработчиком отправки.
Я знаю, что этот тип настройки проверки работает, потому что я использую его в другом месте без проблем.
Я прошел через обработчики изменений, и они работают так, как должны. Однако после появления сообщения об ошибке и выхода из кода оно снова исчезает. Я предполагаю, что проверка входного номера по умолчанию .NET вступает во владение, и так как оба ввода являются действительными числами, он удаляет сообщение об ошибке.
Есть ли способ отключить проверку по умолчанию .NET на входах числового типа, такчто я могу справиться сам и не иметь внешнего кода черного ящика, мешающего моим вещам?
Спасибо.
РЕДАКТИРОВАТЬ:
Вот файлы представления и Default.js вна всякий случай.
@model Coils.CoilParts.Distributor
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
ViewData["Title"] = ViewData["ProgramName"];
}
<h1>Create</h1>
<h4>Distributor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Material" class="control-label"></label>
@Html.DropDownListFor(m => m.Material.Key, ((IEnumerable<SelectListItem>)ViewData["Materials"]))
<span asp-validation-for="Material" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Type" class="control-label"></label>
<input asp-for="Type" class="form-control" />
<span asp-validation-for="Type" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MinTubes" class="control-label"></label>
<input asp-for="MinTubes" class="form-control" />
<span asp-validation-for="MinTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MaxTubes" class="control-label"></label>
<input asp-for="MaxTubes" class="form-control" />
<span asp-validation-for="MaxTubes" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InletSize" class="control-label"></label>
<input asp-for="InletSize" class="form-control" />
<span asp-validation-for="InletSize" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PartNumber" class="control-label"></label>
<input asp-for="PartNumber" class="form-control" />
<span asp-validation-for="PartNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Weight" class="control-label"></label>
<input asp-for="Weight" class="form-control" />
<span asp-validation-for="Weight" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
$(document).ready(function () {
breadcrumbs();
measurementsValidate();
minMaxValidate();
});
var cgi_menus = {
'act': "the Accounting Menu",
'adm': "the Administation Menu",
'car': "the Corrective Action Request Menu",
'cprA': "the A+Pro Menu",
'cprC': "the CoilPro Menu",
'crm': "the Customer Relations Menu",
'dms': "the Document Management Menu",
'eng': "the Engineering Menu",
'etb': "the Engineering Toolbox Menu",
'ldc': "the Refrigeration Load Simulator Menu",
'mgt': "the Management Menu",
'prd': "the Production Menu",
'pur': "the Purchasing Menu",
'qcd': "the Quality Control Menu",
'rpt': "the Report Menu",
'sls': "the Sales Menu",
'sup': "the Administrator's Menu",
'usr': "the User Management Menu",
'utl': "the Utility Menu",
};
function breadcrumbs() {
var tab = {};
localStorage[curURL] = curProgram;
if (sessionStorage.tab) {
tab = JSON.parse(sessionStorage.tab);
}
else {
tab.cur_url = "";
tab.prev_url = "";
tab.history = [];
}
// handle coming from an existing Perl CGI menu
if (!tab.prev_url && document.referrer) {
var menu_info = document.referrer.match(/cgi-s[\\/](\w{3})[\\/]menu(\w?)\.cgi/);
var referrer = new URL(document.referrer);
if (menu_info && referrer.hostname === document.location.hostname) {
tab.cur_url = document.referrer;
var cgi_area = menu_info[1];
if (cgi_area == "cpr") { cgi_area += menu_info[2]; }
localStorage[tab.cur_url] = cgi_menus[cgi_area];
}
}
tab.time = Date.now();
tab.history.push(tab.prev_url);
tab.prev_url = tab.cur_url;
tab.cur_url = curURL;
if (tab.prev_url == tab.cur_url) {
tab.prev_url = tab.history.pop();
}
else if (tab.cur_url == tab.history[tab.history.length - 1]) {
tab.history.pop();
tab.prev_url = tab.history.pop();
}
if (tab.prev_url) {
$("#breadcrumbs").css("display", "inline-block");
$("#breadcrumbs").attr("href", tab.prev_url);
$("#breadcrumbs").html("< Back to " + localStorage[tab.prev_url]);
}
sessionStorage.tab = JSON.stringify(tab);
}
function minMaxValidate() {
$("input[data-val-ismin='true']").each(function (i, ele) {
$(ele).change(function () {
var maxName = $(this).attr("data-val-max");
var minName = $(this).attr("name");
var minValue = parseFloat($(this).val());
var max = $("input[data-val-ismax='true'][name='" + maxName + "']");
var maxValue = max.val();
if (maxValue == "") { return }
maxValue = parseFloat(maxValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(minName + " must not be greater than " + maxName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
$("input[data-val-ismax='true']").each(function (i, ele) {
$(ele).change(function () {
var minName = $(this).attr("data-val-min");
var maxName = $(this).attr("name");
var maxValue = parseFloat($(this).val());
var min = $("input[data-val-ismin='true'][name='" + minName + "']");
var minValue = min.val();
if (minValue == "") { return }
minValue = parseFloat(minValue);
var validationMessage = $("span[data-valmsg-for='" + $(this).attr("name") + "']");
if (minValue > maxValue) {
validationMessage.html(maxName + " must not be less than " + minName);
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
});
}
function measurementsValidate() {
$("input[data-val-measurement='true']").each(function (i, ele) {
var enforceUnits = $(ele).attr("data-val-units");
var units = "";
var hasMax = $(ele).attr("data-val-max");
var max = 0;
var hasMin = $(ele).attr("data-val-min");
var min = 0;
var value = $(ele).val();
var validationRegex = /[0-9/.]+ [a-z./\^0-9*()]+/i;
var name = $("label[for='" + $(ele).attr("name") + "']").html();
var validationMessage = $("span[data-valmsg-for='" + $(ele).attr("name") + "']");
if (typeof (enforceUnits) !== undefined && typeof (enforceUnits) !== false) {
enforceUnits = true;
units = $(ele).attr("data-val-units");
if (hasMax != null && hasMax != false) {
hasMax = true;
max = $(ele).attr("data-val-max");
}
if (hasMin != null && hasMin != false) {
hasMin = true;
min = $(ele).attr("data-val-min");
}
$(ele).change(function () {
var value = $(this).val(); // don't know why this has to be re-evaluated, but it does
if (!value.match(validationRegex)) {
validationMessage.html(name + " must be a valid Measurement. (example: 12 in)");
makeError(validationMessage);
}
else {
$.post("/Validations/Measurements", { EnforceUnits: enforceUnits, Units: units, HasMax: hasMax, Max: max, HasMin: hasMin, Min: min, Value: value })
.done(function (result) {
if (result == "true") {
validationMessage.html("");
makeValid(validationMessage);
}
else {
validationMessage.html(name + result);
makeError(validationMessage);
}
})
.fail(function () {
validationMessage.html("");
makeValid(validationMessage);
});
}
});
}
else {
$(ele).change(function () {
if (!value.match(validationRegex)) {
validationMessage.html(name + " must be a valid Measurement. (example: 12 in)");
makeError(validationMessage);
}
else {
validationMessage.html("");
makeValid(validationMessage);
}
});
}
});
}
function makeError(ele) {
$(ele).removeClass("field-validation-valid");
$(ele).addClass("field-validation-error");
$(ele).closest("form").unbind("submit");
$(ele).closest("form").submit(function () { return false });
}
function makeValid(ele) {
$(ele).removeClass("field-validation-error");
$(ele).addClass("field-validation-valid");
$(ele).closest("form").unbind("submit");
$(ele).closest("form").submit(checkFormValidation);
}
function checkFormValidation() {
if ($(this).find(".field-validation-error")[0]) {
return false;
}
return true;
}
РЕДАКТИРОВАТЬ 2:
Вот ГИФ о том, что происходит: https://i.imgur.com/eAiqxQJ.mp4