Атрибут MaxLength не генерирует атрибуты проверки на стороне клиента

83

У меня любопытная проблема с проверкой на стороне клиента ASP.NET MVC3. У меня следующий класс:

public class Instrument : BaseObject
{
    public int Id { get; set; }

    [Required(ErrorMessage = "Name is required.")]
    [MaxLength(40, ErrorMessage = "Name cannot be longer than 40 characters.")]
    public string Name { get; set; }
}

С моей точки зрения:

<div class="editor-field">
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)
</div>

А вот сгенерированный HTML-код для текстового поля для этого поля:

<input class="text-box single-line" data-val="true" data-val-required="Name is required." id="Name" name="Name" type="text" value="">

Никаких признаков MaxLengthAttribute, но все остальное вроде работает.

Есть идеи, что не так?

Мэтт Дженкинс
источник

Ответы:

151

Попробуйте использовать [StringLength]атрибут:

[Required(ErrorMessage = "Name is required.")]
[StringLength(40, ErrorMessage = "Name cannot be longer than 40 characters.")]
public string Name { get; set; }

Это для целей проверки. Если вы хотите установить, например, атрибут maxlength на входе, вы можете написать собственный поставщик метаданных аннотаций данных, как показано в этом сообщении, и настроить шаблоны по умолчанию .

Дарин Димитров
источник
3
Большое спасибо. Если кому-то интересно, я проверил, что EF Code First создает столбец DB с максимальной длиной, установленной атрибутом StringLength. :)
Мэтт Дженкинс
Но это не ответ. Потому что атрибут MinLength тоже не работает
Григорий
@Greg атрибут StringLength может указывать максимальную и минимальную длину.
Калеб Вир
Что делать, если вы не хотите указывать максимальную длину, а только минимальную? Вы предложили в основном функциональный обходной путь, но он не решает проблему, связанную с неправильной проверкой атрибута проверки.
Джереми Головач
7
@JeremyHolovacs, если вы не хотите указывать максимальное значение, вы просто указываете его int.MaxValueкак максимальную длину, а затем устанавливаете для свойства MinLength любую необходимую минимальную длину. Так что нет, это не просто функциональный обходной путь. Это тоже работает на практике.
Дарин Димитров
36

Я просто использовал фрагмент jquery для решения этой проблемы.

$("input[data-val-length-max]").each(function (index, element) {
   var length = parseInt($(this).attr("data-val-length-max"));
   $(this).prop("maxlength", length);
});

Селектор находит все элементы, для которых установлен атрибут data-val-length-max. Это атрибут, который установит атрибут проверки StringLength.

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

Просто добавьте это к своей функции готовности документа, и все готово.

Ник Харрисон
источник
Это довольно красиво.
TheOptimusPrimus 07
4
вы можете использовать .data ("val-length-max") вместо .attr ("data-val-length-max") :)
hatsrumandcode
8

MaxLengthAttributeработает после обновления MVC 5.1: примечания к изменениям

Михаил Логутов
источник
14
Теперь он работает для проверки, но MVC по-прежнему не применяет maxlengthатрибут к inputэлементу.
ladenedge
1
Я написал расширение фреймворка , которое делает именно это @ladenedge
Кристиан Голлхардт
8

В MVC 4 Если вы хотите maxlenght в тексте типа ввода? Вы можете !

@Html.TextBoxFor(model => model.Item3.ADR_ZIP, new { @class = "gui-input ui-oblig", @maxlength = "5" })
Сен-Мартен Гийом
источник
4

Реквизит @ Nick-Harrison за его ответ:

$("input[data-val-length-max]").each(function (index, element) {
var length = parseInt($(this).attr("data-val-length-max"));
$(this).prop("maxlength", length);
});

Мне было интересно, для чего там parseInt ()? Я упростил это до этого без проблем ...

$("input[data-val-length-max]").each(function (index, element) {
    element.setAttribute("maxlength", element.getAttribute("data-val-length-max"))
});

Я бы прокомментировал ответ Ника, но пока у меня недостаточно репутации.

EamonnM
источник
3

У меня была такая же проблема, и я смог решить ее, реализовав интерфейс IValidatableObject в моей модели представления.

public class RegisterViewModel : IValidatableObject
{
    /// <summary>
    /// Error message for Minimum password
    /// </summary>
    public static string PasswordLengthErrorMessage => $"The password must be at least {PasswordMinimumLength} characters";

    /// <summary>
    /// Minimum acceptable password length
    /// </summary>
    public const int PasswordMinimumLength = 8;

    /// <summary>
    /// Gets or sets the password provided by the user.
    /// </summary>
    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    /// <summary>
    /// Only need to validate the minimum length
    /// </summary>
    /// <param name="validationContext">ValidationContext, ignored</param>
    /// <returns>List of validation errors</returns>
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var errorList = new List<ValidationResult>();
        if ((Password?.Length ?? 0 ) < PasswordMinimumLength)
        {
            errorList.Add(new ValidationResult(PasswordLengthErrorMessage, new List<string>() {"Password"}));
        }
        return errorList;
    }
}

Тогда разметка в Razor ...

<div class="form-group">
    @Html.LabelFor(m => m.Password)
    @Html.PasswordFor(m => m.Password, new { @class = "form-control input-lg" }
    <div class="password-helper">Must contain: 8 characters, 1 upper-case, 1 lower-case
    </div>
    @Html.ValidationMessagesFor(m => m.Password, new { @class = "text-danger" })
</div>

Это действительно хорошо работает. Если я попытаюсь использовать вместо этого [StringLength], то обработанный HTML будет неверным. Проверка должна отображаться как:

<span class="text-danger field-validation-invalid field-validation-error" data-valmsg-for="Password" data-valmsg-replace="true"><span id="Password-error" class="">The Password should be a minimum of 8 characters long.</span></span>

С StringLengthAttribute обработанный HTML отображается как ValidationSummary, что неверно. Самое смешное, что когда валидатор терпит неудачу, отправка по-прежнему блокируется!

СкоттиМакДев
источник
2

StringLength отлично работает, я использовал его так:

[StringLength(25,MinimumLength=1,ErrorMessage="Sorry only 25 characters allowed for 
              ProductName")]
public string ProductName { get; set; }

или просто используйте RegularExpressionбез StringLength:

[RegularExpression(@"^[a-zA-Z0-9'@&#.\s]{1,25}$", ErrorMessage = "Reg Says Sorry only 25 
                   characters allowed for ProductName")]    
public string ProductName { get; set; }

но для меня вышеуказанные методы дали ошибку при отображении, потому что у меня уже было поле ProductName в базе данных, которое имело более 25 символов

Итак, наконец, я наткнулся на этот и этот пост и попытался проверить без такой модели :

 <div class="editor-field">
 @Html.TextBoxFor(model => model.ProductName, new
 {
 @class = "form-control",
 data_val = "true",
 data_val_length = "Sorry only 25 characters allowed for ProductName",
 data_val_length_max = "25",
 data_val_length_min = "1"
 })
 <span class="validation"> @Html.ValidationMessageFor(model => model.ProductName)</span>
 </div>

это решило мою проблему, вы также можете выполнить проверку вручную с помощью jquery или с помощью ModelState.AddModelError

надежда кому-то помогает.

Шайджу Т
источник
2

Я знаю, что очень опаздываю на вечеринку, но наконец выяснил, как мы можем зарегистрировать MaxLengthAttribute.

Для начала нам понадобится валидатор:

public class MaxLengthClientValidator : DataAnnotationsModelValidator<MaxLengthAttribute>
{
    private readonly string _errorMessage;
    private readonly int _length;


    public MaxLengthClientValidator(ModelMetadata metadata, ControllerContext context, MaxLengthAttribute attribute)
    : base(metadata, context, attribute)
    {
        _errorMessage = attribute.FormatErrorMessage(metadata.DisplayName);
        _length = attribute.Length;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = _errorMessage,
            ValidationType = "length"
        };

        rule.ValidationParameters["max"] = _length;
        yield return rule;
    }
}

Ничего особенного. В конструкторе мы сохраняем некоторые значения из атрибута. В GetClientValidationRulesмы устанавливаем правила. ValidationType = "length"отображается data-val-lengthкаркасом. rule.ValidationParameters["max"]для data-val-length-maxатрибута.

Теперь, когда у вас есть валидатор, вам нужно только зарегистрировать его global.asax:

protected void Application_Start()
{
    //...

    //Register Validator
    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MaxLengthAttribute), typeof(MaxLengthClientValidator));
}

Et voila, это просто работает.

Кристиан Голлхардт
источник
1

Я пробовал это для всех входных данных в моем html-документе (текстовое поле, входы и т. Д.), У которых было свойство data-val-length-max, и он работает правильно.

$(document).ready(function () {
    $(":input[data-val-length-max]").each(function (index, element) {
        var length = parseInt($(this).attr("data-val-length-max"));
        $(this).prop("maxlength", length);
    });
});
Марио Дуран Альварес
источник
0

Это может заменить MaxLength и MinLength

[StringLength(40, MinimumLength = 10 , ErrorMessage = "Name cannot be longer than 40 characters and less than 10")]
amal50
источник
0
<input class="text-box single-line" data-val="true" data-val-required="Name is required." 
    id="Name1" name="Name" type="text" value="">

$('#Name1').keypress(function () {
    if (this.value.length >= 5) return false;
});
Нитья
источник
6
Добавьте описание
King Stone