ASP.NET Core 2 - проверка ввода номера по умолчанию переопределяет мою пользовательскую проверку клиента - PullRequest
0 голосов
/ 02 октября 2019

У меня есть два входа, которые мне нужно проверить друг против друга. Они минимальные и максимальные. Вот часть моего представления, определяющая их.

<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

1 Ответ

0 голосов
/ 02 октября 2019

Как это часто бывает, решением является "Если вы не можете победить их, присоединяйтесь к ним".

Вместо отключения проверки jQuery для элементов, которые я настраиваю, решение простоопираться на библиотеку валидации jQuery и правильно ее использовать. На стороне .NET все остается таким же, но функция minMaxValidate() становится такой:

function minMaxValidate() {
    $.validator.addMethod("maxTo", function (value, element, param) {
        var $element = $(element), $min;

        if (typeof (param) === "string") {
            $min = $(param);
        } else {
            $min = $("input[name='" + $element.attr("data-val-min") + "']");
        }

        if (this.settings.onfocusout) {
            $min.off(".validate-maxTo").on("blur.validate-maxTo", function () {
                $element.valid();
            });
        }
        return parseInt(value) >= parseInt($min.val());
    }, "Max must not be less than min");

    $("input[data-val-ismax]").each(function (i, ele) {
        $(ele).rules('add', { maxTo: true });
    });

    $.validator.addMethod("minTo", function (value, element, param) {
        var $element = $(element), $max;

        if (typeof (param) === "string") {
            $max = $(param);
        } else {
            $max = $("input[name='" + $element.attr("data-val-max") + "']");
        }

        if (this.settings.onfocusout) {
            $max.off(".validate-minTo").on("blur.validate-minTo", function () {
                $element.valid();
            });
        }
        return parseInt(value) <= parseInt($max.val());
    }, "Min must not be greater than max");

    $("input[data-val-ismin]").each(function (i, ele) {
        $(ele).rules('add', { minTo: true });
    });
}

Это добавляет методы и правила для нормальной проверки jQuery для запуска.

Это делаетименно то, что я хочу. Спасибо Этот пост за помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...