MVC3 ненавязчивая группа проверки входов - PullRequest
42 голосов
/ 28 апреля 2011

Мне нужно проверить 3 или более полей ввода (требуется как минимум одно). Например, у меня есть электронная почта, факс, телефон.

Мне нужно заполнить как минимум ОДИН. Мне нужна ненавязчивая проверка и сервера, и клиента. пожалуйста помоги. Я посмотрел на метод «Сравнить» и попытался изменить его, но не повезло. пожалуйста помоги. спасибо

Ответы [ 4 ]

84 голосов
/ 28 апреля 2011

Вы можете написать собственный атрибут:

public class AtLeastOneRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _properties;
    public AtLeastOneRequiredAttribute(params string[] properties)
    {
        _properties = properties;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (_properties == null || _properties.Length < 1)
        {
            return null;
        }

        foreach (var property in _properties)
        {
            var propertyInfo = validationContext.ObjectType.GetProperty(property);
            if (propertyInfo == null)
            {
                return new ValidationResult(string.Format("unknown property {0}", property));
            }

            var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))
            {
                return null;
            }

            if (propertyValue != null)
            {
                return null;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "atleastonerequired"
        };
        rule.ValidationParameters["properties"] = string.Join(",", _properties);

        yield return rule;
    }
}

, который можно использовать для украшения одного из свойств модели вашего представления (того, которое вы хотите выделить в случае неудачной проверки):

public class MyViewModel
{
    [AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]
    public string Email { get; set; }
    public string Fax { get; set; }
    public string Phone { get; set; }
}

и затем простой контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

Отображение следующего представления, которое позаботится об определении пользовательского адаптера валидатора на стороне клиента:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
    jQuery.validator.unobtrusive.adapters.add(
        'atleastonerequired', ['properties'], function (options) {
            options.rules['atleastonerequired'] = options.params;
            options.messages['atleastonerequired'] = options.message;
        }
    );

    jQuery.validator.addMethod('atleastonerequired', function (value, element, params) {
        var properties = params.properties.split(',');
        var values = $.map(properties, function (property, index) {
            var val = $('#' + property).val();
            return val != '' ? val : null;
        });
        return values.length > 0;
    }, '');
</script>

@using (Html.BeginForm())
{
    @Html.ValidationSummary(false)

    <div>
        @Html.LabelFor(x => x.Email)
        @Html.EditorFor(x => x.Email)
    </div>

    <div>
        @Html.LabelFor(x => x.Fax)
        @Html.EditorFor(x => x.Fax)
    </div>

    <div>
        @Html.LabelFor(x => x.Phone)
        @Html.EditorFor(x => x.Phone)
    </div>

    <input type="submit" value="OK" />
}

Конечно, пользовательский адаптер иПравило валидатора должно быть выведено в отдельный файл javascript, чтобы избежать смешивания скрипта с разметкой.

5 голосов
/ 02 сентября 2011

Я потратил более 36 часов, почему код не работает для меня .. В конце я обнаружил, что в моем случае я не должен был использовать имена свойств в этой строке кода

[AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]

Но мне пришлось использовать идентификаторы элементов HTMl вместо имен свойств, и это работало как по волшебству.

Разместите это здесь, если это может кому-то помочь.

2 голосов
/ 28 апреля 2011

Поскольку вы используете MVC 3, взгляните на отличное видео , которое Брэд Уилсон имел на mvcConf.Там есть все, что нужно для создания клиент + сервер Ненавязчивая проверка

1 голос
/ 22 августа 2016

@ Решение Дарина Кимитрова, вероятно, является стандартом создания настраиваемого атрибута проверки, который работает с ненавязчивой проверкой. Однако использование пользовательских атрибутов проверки для ненавязчивой проверки имеет некоторые недостатки, такие как:

  • Пользовательский атрибут проверки привязан только к одному свойству, поэтому проверка клиента не будет работать, если на двух других входах есть событие изменения.
  • Сообщение об ошибке отлично работает с ValidationSummary, но если вы хотите отобразить 1 сообщение об ошибке для всей группы (что я считаю нормой), это будет почти невозможно.
  • Чтобы избежать первой проблемы, мы можем добавить пользовательский атрибут проверки для каждого элемента в группе, что вызовет еще одну проблему: мы должны проверить все элементы группы вместо того, чтобы останавливаться на первом недопустимом элементе группы. И, конечно же, вторая проблема - отдельные сообщения об ошибках для каждого элемента - все еще остается.

Существует еще один способ обработки проверки входных данных на стороне клиента с использованием установки групп в jquery validator (https://jqueryvalidation.org/validate/#groups).). Единственная проблема (и большая) заключается в том, что ненавязчивая проверка не поддерживает группы проверки jquery по умолчанию. поэтому нам нужно немного настроить.

Хотя этот ответ вряд ли является «ненавязчивым», на мой взгляд, стоит попытаться избавиться от ненужного усложнения кода, если ваша конечная цель - проверить группу входов при использовании ненавязчивой библиотеки валидатора Microsoft.

Во-первых, поскольку групповые настройки валидатора jquery по умолчанию недоступны в ненавязчивом валидаторе jquery, мы должны переопределить ненавязчивые настройки (ссылка Как я могу настроить ненавязчивую валидацию в ASP.NET MVC 3 в соответствии с моим стилем? )

$("form").on('submit', function () {
    var form = this;
    var validator = $(this).data("validator");

    if (validator.settings && !validator.settings.submitHandler) {
        $.extend(true, validator.settings.rules, validationSettings.rules);
        $.extend(true, validator.settings.groups, validationSettings.groups);
        initGroups(validator);

        var fnErrorReplacement = validator.settings.errorPlacement;
        validator.settings.errorPlacement = function (error, element) {
            validationSettings.errorPlacement(error, element, fnErrorReplacement, form);
        }
        validator.settings.submitHandler = formSubmitHandler;
    }
});

function formSubmitHandler(form) {
    form.submit();
}

После этого переопределите ненавязчивые группы валидатора, правила и настройки errorPlacement.

var validationSettings = {
groups: {
    checkboxgroup: "Email Fax Phone"
},
rules: {
    Email: {
        required: function () {
            return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
        }
    },
    Fax: {
        required: function () {
            return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
        }
    },
    Phone: {
        required: function () {
            return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
        }
    }
}
,
errorPlacement: function (error, element, fnUnobtrusive, form) {
    switch (element.attr("name")) {
        case "Email":
        case "Fax":
        case "Phone":
            onGroupError(error, "CheckBoxGroup", form);
            break;
        default:
            fnUnobtrusive(error, element);
            break;
    }
}
}

function validateCheckboxGroup(names) {
var result = true;
$.each(names, function (index, value) {
    if ($(value).is(":checked")) {
        result = false;
    }
});
return result;
}

Поскольку ненавязчивый валидатор не реализует настройку групп валидатора jquery, нам нужно повторно использовать две функции из двух библиотек для: (1) имен групп .split (повторное использование кода из валидатора jquery) и (2) добавления элемента ошибки без удаления класс 'input-validation-error' (повторное использование функции onError из ненавязчивой библиотеки).

function initGroups(validators) {
validators.groups = {};
$.each(validators.settings.groups,
    function (key, value) {
        if (typeof value === "string") {
            value = value.split(/\s/);
        }
        $.each(value,
            function (index, name) {
                validators.groups[name] = key;
            });
    });
}

function onGroupError(error, inputElementName, form) {
var container = $(form).find("[data-valmsg-for='" + inputElementName + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);

if (replace) {
    container.empty();
    error.appendTo(container);
}
else {
    error.hide();
}
}

Наконец, используйте HtmlExtensions.ValidationMessage, чтобы создать диапазон ошибок для группы флажков.

@Html.ValidationMessage("CheckBoxGroup", new { @class = "text-danger" }) 

Необходимо сохранить класс «input-validation-error», чтобы средство проверки jquery проверило все 3 элемента (Email, Phone, Fax) группы флажков в целом, вместо проверки одного за другим. Ненавязчивая библиотека проверки удаляет этот класс по умолчанию для функции onError, поэтому мы должны настроить ее как показано в функции onGroupError выше.

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