MaxLength-Attribut generiert keine clientseitigen Validierungsattribute

82

Ich habe ein merkwürdiges Problem mit der clientseitigen Validierung von ASP.NET MVC3. Ich habe folgende Klasse:

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; }
}

Aus meiner Sicht:

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

Und hier ist der generierte HTML-Code, den ich für das Textfeld für dieses Feld erhalte:

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

Keine Spur von MaxLengthAttribute, aber alles andere scheint zu funktionieren.

Irgendwelche Ideen, was falsch läuft?

Matt Jenkins
quelle

Antworten:

150

Versuchen Sie es mit dem [StringLength]Attribut:

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

Das dient zu Validierungszwecken. Wenn Sie beispielsweise das Attribut maxlength für die Eingabe festlegen möchten, können Sie einen benutzerdefinierten Metadatenanbieter für Datenanmerkungen schreiben, wie in diesem Beitrag gezeigt, und die Standardvorlagen anpassen .

Darin Dimitrov
quelle
3
Vielen Dank. Falls sich jemand wundert, habe ich überprüft, ob EF Code First die DB-Spalte mit der maximalen Länge erstellt, die durch das StringLength-Attribut vorgegeben wird. :)
Matt Jenkins
Dies ist jedoch nicht die Antwort. Weil das MinLength-Attribut auch nicht funktioniert
Hryhorii
@Greg, das StringLength-Attribut kann eine maximale und minimale Länge angeben.
Caleb Vear
Was ist, wenn Sie keine maximale Länge angeben möchten, sondern nur eine minimale? Sie haben eine meist funktionale Problemumgehung vorgeschlagen, die jedoch nicht das Problem behebt, dass das Validierungsattribut nicht ordnungsgemäß validiert wird.
Jeremy Holovacs
6
@JeremyHolovacs, wenn Sie kein Maximum angeben möchten, geben Sie einfach die int.MaxValuemaximale Länge an und setzen die MinLength- Eigenschaft auf die gewünschte Mindestlänge. Nein, es ist nicht nur eine funktionale Problemumgehung. Es ist eines, das auch in der Praxis funktioniert.
Darin Dimitrov
36

Ich habe nur einen Ausschnitt von jquery verwendet, um dieses Problem zu lösen.

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

Der Selektor findet alle Elemente, für die ein Attributsatz data-val-length-max festgelegt ist. Dies ist das Attribut, das das StringLength-Validierungsattribut festlegt.

Jede Schleife durchläuft diese Übereinstimmungen und analysiert den Wert für dieses Attribut und weist ihn der Eigenschaft mxlength zu, die festgelegt werden sollte.

Fügen Sie dies einfach zu Ihrer Dokumentbereitschaftsfunktion hinzu, und schon kann es losgehen.

Nick Harrison
quelle
Das ist ziemlich schlau.
TheOptimusPrimus
4
Sie können .data ("val-length-max") anstelle von .attr ("data-val-length-max") verwenden :)
hatsrumandcode
8

In MVC 4 Wenn Sie eine maximale Länge im Eingabetyp Text wünschen? Sie können !

@Html.TextBoxFor(model => model.Item3.ADR_ZIP, new { @class = "gui-input ui-oblig", @maxlength = "5" })
Saint-Martin Guillaume
quelle
4

Props an @ Nick-Harrison für seine Antwort:

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

Ich habe mich gefragt, wozu parseInt () da ist. Ich habe es ohne Probleme vereinfacht ...

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

Ich hätte Nicks Antwort kommentiert, aber noch nicht genug Repräsentanten.

EamonnM
quelle
3

Ich hatte das gleiche Problem und konnte es lösen, indem ich die IValidatableObject-Schnittstelle in meinem Ansichtsmodell implementierte.

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;
    }
}

Das Markup im Rasiermesser ist dann ...

<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>

Das funktioniert wirklich gut. Wenn ich stattdessen versuche, [StringLength] zu verwenden, ist der gerenderte HTML-Code einfach nicht korrekt. Die Validierung sollte wie folgt erfolgen:

<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>

Mit dem StringLengthAttribute wird der gerenderte HTML-Code als ValidationSummary angezeigt, was nicht korrekt ist. Das Lustige ist, dass wenn der Validator ausfällt, die Übermittlung immer noch blockiert ist!

ScottyMacDev
quelle
2

StringLength funktioniert super, ich habe es so benutzt:

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

oder einfach RegularExpressionohne StringLength verwenden:

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

aber für mich oben Methoden gaben Fehler in der Anzeigeansicht, weil ich bereits ProductName Feld in der Datenbank hatte, die mehr als 25 Zeichen hatte

Also bin ich endlich auf diesen und diesen Beitrag gestoßen und habe versucht, ohne dieses Modell zu validieren :

 <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>

Dies hat mein Problem gelöst. Sie können die Validierung auch manuell mit jquery oder ModelState.AddModelError durchführen

Hoffnung hilft jemandem.

Shaijut
quelle
2

Ich weiß, dass ich sehr spät zur Party komme, aber ich habe endlich herausgefunden, wie wir die registrieren können MaxLengthAttribute .

Zuerst brauchen wir einen Validator:

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;
    }
}

Nichts wirklich Besonderes. Im Konstruktor speichern wir einige Werte aus dem Attribut. In der setzen GetClientValidationRuleswir eine Regel. ValidationType = "length"wird data-val-lengthvom Framework zugeordnet. rule.ValidationParameters["max"]ist für das data-val-length-maxAttribut.

Jetzt, da Sie einen Validator haben, müssen Sie ihn nur noch registrieren in global.asax:

protected void Application_Start()
{
    //...

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

Et voila, es funktioniert einfach.

Christian Gollhardt
quelle
1

Ich habe dies für alle Eingaben in meinem HTML-Dokument (Textbereich, Eingaben usw.) versucht, die die Eigenschaft data-val-length-max hatten und ordnungsgemäß funktionieren.

$(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);
    });
});
Mario Durán Alvarez
quelle
0

Dies kann die MaxLength und die MinLength ersetzen

[StringLength(40, MinimumLength = 10 , ErrorMessage = "Name cannot be longer than 40 characters and less than 10")]
amal50
quelle
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;
});
Nithya
quelle
6
Bitte Beschreibung hinzufügen
King Stone