2017-02-03 2 views
3

Ich entwickle eine benutzerdefinierte ASP.NET MVC 5.2.3 Annotation für die Validierung in Visual Studio 2015. Es muss eine beliebige Anzahl von Feldern nehmen und sicherstellen, dass, wenn man einen Wert hat, sie müssen alle einen Wert haben; Wenn sie alle null/leer sind, sollte es in Ordnung sein.ASP.NET MVC benutzerdefinierte mehrere Felder Validierung

Einige Beispiele haben dazu beigetragen:

Aber ich bin nicht sicher, wie die clientseitige Validierung zu tun, wo Sie eine haben unbekannte Anzahl von Feldern wird validiert.

Wie übergeben Sie das an den Client mit der Implementierung der GetClientValidationRules() Methode der IClientValidatable Schnittstelle?

Wie kann ich diese neue Datenannotation auch auf die Eigenschaften in meinem Ansichtsmodell anwenden? Würde es so aussehen?

[MultipleRequired("AppNumber", "UserId", /* more fields */), ErrorMessage = "Something..."] 
[DisplayName("App #")] 
public int AppNumber { get; set; } 

[DisplayName("User ID")] 
public int UserId { get; set; } 

Hier ist so weit ich mit der MultipleRequiredAttribute benutzerdefinierten Daten Annotation-Klasse bekommen konnte:

public class MultipleRequiredAttribute : ValidationAttribute, IClientValidatable 
{ 
    private readonly string[] _fields; 
    public MultipleRequiredAttribute(params string[] fields) 
    { 
     _fields = fields; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     // If any field has value, then all must have value 
     var anyHasValue = _fields.Any(f => !string.IsNullOrEmpty(f)); 

     if (!anyHasValue) return null; 

     foreach (var field in _fields) 
     { 
      var property = validationContext.ObjectType.GetProperty(field); 
      if (property == null) 
       return new ValidationResult($"Property '{field}' is undefined."); 

      var fieldValue = property.GetValue(validationContext.ObjectInstance, null); 

      if (string.IsNullOrEmpty(fieldValue?.ToString())) 
       return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
     } 

     return null; 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     yield return new ModelClientValidationRule 
     { 
      ErrorMessage = ErrorMessage, 
      ValidationType = "multiplerequired" 
     }; 
    } 
} 

Danke.

+0

Sie eine benutzerdefinierte Funktion für Plugin js jquery Validate bauen – Steve

+2

Beginnen Sie mit dem Lesen der vollständigen Anleitung zur Validierung in ASP.NET MVC 3 - Teil 2] (http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net -mvc-3-Teil-2). Fügen Sie in Ihrer 'GetClientValidationRules()' Methode eine 'ModelClientValidationRule' hinzu, in der Sie eine durch Kommas getrennte Liste der Eigenschaftsnamen übergeben können - also Ihre' fields' Werte - die in den clientseitigen Skripten analysiert und verwendet werden können (Wenn Sie Probleme haben, lassen Sie es mich wissen und ich werde eine Antwort hinzufügen, werde aber keine Chance für ein paar Stunden bekommen) –

+0

Danke, @StephenMuecke! Eines meiner Probleme war, wie man die Werte an den Kunden weitergibt. – Alex

Antwort

1

Um Clientseite Validierung zu erhalten, müssen Sie die Werte der ‚anderen Eigenschaften‘ passieren in den ModelClientValidationRule durch die .Add() Methode der Regeln ValidationParameters Eigenschaft verwenden und dann den Client-Seite Skripte schreiben, um die Regeln in der die $.validator.

Aber zuerst gibt es ein paar andere Probleme mit Ihrem Attribut zu lösen. Zuerst sollten Sie Ihre foreach-Schleife nur ausführen, wenn der Wert der Eigenschaft, auf die Sie das Attribut angewendet haben, null ist. Zweitens ist die Rückgabe einer ValidationResult, wenn eine der "anderen Eigenschaften" nicht existiert, für einen Benutzer verwirrend und bedeutungslos und Sie sollten es einfach ignorieren.

Das Attribut Code sollte sein (beachten Sie änderte ich den Namen des Attributs)

public class RequiredIfAnyAttribute : ValidationAttribute, IClientValidatable 
{ 
    private readonly string[] _otherProperties; 
    private const string _DefaultErrorMessage = "The {0} field is required"; 

    public RequiredIfAnyAttribute(params string[] otherProperties) 
    { 
     if (otherProperties.Length == 0) // would not make sense 
     { 
      throw new ArgumentException("At least one other property name must be provided"); 
     } 
     _otherProperties = otherProperties; 
     ErrorMessage = _DefaultErrorMessage; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     if (value == null) // no point checking if it has a value 
     { 
      foreach (string property in _otherProperties) 
      { 
       var propertyName = validationContext.ObjectType.GetProperty(property); 
       if (propertyName == null) 
       { 
        continue; 
       } 
       var propertyValue = propertyName.GetValue(validationContext.ObjectInstance, null); 
       if (propertyValue != null) 
       { 
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
       } 
      } 
     } 
     return ValidationResult.Success; 
    } 
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ValidationType = "requiredifany", 
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
     }; 
     /pass a comma separated list of the other propeties 
     rule.ValidationParameters.Add("otherproperties", string.Join(",", _otherProperties)); 
     yield return rule; 
    } 
} 

Die Skripte

dann wird auf Client-Seite
sandtrapValidation = { 
    getDependentElement: function (validationElement, dependentProperty) { 
     var dependentElement = $('#' + dependentProperty); 
     if (dependentElement.length === 1) { 
      return dependentElement; 
     } 
     var name = validationElement.name; 
     var index = name.lastIndexOf(".") + 1; 
     var id = (name.substr(0, index) + dependentProperty).replace(/[\.\[\]]/g, "_"); 
     dependentElement = $('#' + id); 
     if (dependentElement.length === 1) { 
      return dependentElement; 
     } 
     // Try using the name attribute 
     name = (name.substr(0, index) + dependentProperty); 
     dependentElement = $('[name="' + name + '"]'); 
     if (dependentElement.length > 0) { 
      return dependentElement.first(); 
     } 
     return null; 
    } 
} 

$.validator.unobtrusive.adapters.add("requiredifany", ["otherproperties"], function (options) { 
    var element = options.element; 
    var otherNames = options.params.otherproperties.split(','); 
    var otherProperties = []; 
    $.each(otherNames, function (index, item) { 
     otherProperties.push(sandtrapValidation.getDependentElement(element, item)) 
    }); 
    options.rules['requiredifany'] = { 
     otherproperties: otherProperties 
    }; 
    options.messages['requiredifany'] = options.message; 
}); 

$.validator.addMethod("requiredifany", function (value, element, params) { 
    if ($(element).val() != '') { 
     // The element has a value so its OK 
     return true; 
    } 
    var isValid = true; 
    $.each(params.otherproperties, function (index, item) { 
     if ($(this).val() != '') { 
      isValid = false; 
     } 
    }); 
    return isValid; 
}); 
+0

Danke, @StephenMuecke.Ich bin mit der Logik des 'sandtrapValidation'-Codes verloren, können Sie das etwas erklären? – Alex

+1

Es ist eine allgemeine Funktion zum Finden eines assoziierten Elements in Das DOM. Möglicherweise haben Sie ein Modell mit Eigenschaften, die komplexe Objekte oder Sammlungen sind, so dass es als Eingaben mit (sagen wir) 'name =" Mitarbeiter [0] .FirstName "id =" Employees_0__FirstName "' und 'name =" Mitarbeiter [0] .LastName "id =" Employees_0__LastName "'. Angenommen, Sie möchten den 'LastName' bestätigen, wenn 'FirstName' angegeben ist. Alles, was Sie in der 'GetClientValidationRules()' Methode übergeben können, ist der Name des andere Eigenschaft, dh 'Last Name' –

+1

Die Methode prüft zuerst, ob das DOM ein Element mit 'id = "LastName" 'enthält. Für ein einfaches Objekt wird ein Element zurückgegeben. Aber in diesem Fall wird der nächste Teil der Funktion nicht den Namen des aktuellen Elements (name = "Employees [0] .FirstName" ') erhalten und erhält den Teil links vom letzten Punkt (' Mitarbeiter [0] ') und hängt an eine andere Eigenschaft an, um' Employees [0] .LastName' zu ​​generieren. Da die Suche nach 'id' schneller ist als nach 'name', erzeugt '.replace() '' Employees_0__LastName' und es wird nach diesem Element gesucht. –

Verwandte Themen