144 votes

Désactiver l'attribut de validation obligatoire dans certaines circonstances

Je me demandais s'il était possible de désactiver l'attribut de validation obligatoire dans certaines actions du contrôleur. Je me pose cette question parce que sur l'un de mes formulaires d'édition, je ne demande pas à l'utilisateur de saisir des valeurs pour des champs qu'il a déjà spécifiés auparavant. Cependant, j'implémente une logique qui, lorsqu'il entre une valeur, utilise une logique spéciale pour mettre à jour le modèle, par exemple en hachant une valeur, etc.

Avez-vous des suggestions sur la façon de contourner ce problème ?

EDIT :
Et oui, la validation du client est un problème ici aussi, car elle ne leur permettra pas de soumettre le formulaire sans saisir de valeur.

3 votes

+1 bonne question. Il serait bon de mentionner la validation du client ici. Une option consiste à supprimer le RequiredAttr complètement et faire une vérification côté serveur lorsque vous doivent le faire. Mais cela serait délicat pour le client

4 votes

Des points pour toute personne qui couvre également l'invalidité certains Les champs de validation des clients (sans enlever les références à la validation jquery)

0 votes

Peut-être que je ne comprends pas ce que vous voulez dire, mais si l'utilisateur a déjà spécifié les valeurs au préalable, alors ces valeurs sont déjà présentes et passent donc la validation requise. Voulez-vous dire autre chose ?

80voto

Darin Dimitrov Points 528142

Ce problème peut être facilement résolu en utilisant des modèles de vue. Les modèles de vue sont des classes qui sont spécifiquement adaptées aux besoins d'une vue donnée. Ainsi, par exemple, dans votre cas, vous pourriez avoir les modèles de vue suivants :

public UpdateViewView
{
    [Required]
    public string Id { get; set; }

    ... some other properties
}

public class InsertViewModel
{
    public string Id { get; set; }

    ... some other properties
}

qui seront utilisés dans les actions correspondantes du contrôleur :

[HttpPost]
public ActionResult Update(UpdateViewView model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
    ...
}

0 votes

Pas toujours vrai si vous avez un booléen/bit qui n'est pas nullable. Mais cela ne fait pas vraiment de différence puisque cela va finir par être vrai ou faux. J'avais du css pour mettre en évidence les champs obligatoires et il a faussement mis en évidence l'élément CheckBoxFor. Ma solution : $("#IsValueTrue").removeAttr("data-val-required") ;

0 votes

Dans la mise à jour, nous avons généralement (FormCollection collection). Pourriez-vous expliquer comment vous utilisez le modèle comme paramètre ?

4 votes

Non, nous n'avons pas l'habitude Update(FormCollection collection) En tout cas, je ne le fais jamais. Je définis et utilise toujours un modèle de vue spécifique : Update(UpdateViewView model) .

56voto

Adrian Smith Points 241

Si vous souhaitez simplement désactiver la validation pour un seul champ du côté client, vous pouvez remplacer les attributs de validation comme suit :

@Html.TextBoxFor(model => model.SomeValue, 
                new Dictionary<string, object> { { "data-val", false }})

21 votes

Ce qui a fonctionné pour moi via jQuery : $("#SomeValue").removeAttr("data-val-required") ;

7 votes

J'aime cette approche, mais j'ai dû analyser à nouveau les attributs de validation du formulaire en utilisant : $('form').removeData('unobtrusiveValidation') ; $('form').removeData('validator') ; $.validator.unobtrusive.parse('selector for your form') ;

17 votes

@Html.TexBoxFor(model => model.SomeValue, new { data_val = false }) - plus facile à lire IMO.

45voto

PhilDulac Points 147

Je sais que cette question a déjà reçu une réponse il y a longtemps et que la réponse acceptée fera le travail. Mais il y a une chose qui me dérange : devoir copier 2 modèles uniquement pour désactiver une validation.

Voici ma suggestion :

public class InsertModel
{
    [Display(...)]
    public virtual string ID { get; set; }

    ...Other properties
}

public class UpdateModel : InsertModel
{
    [Required]
    public override string ID
    {
        get { return base.ID; }
        set { base.ID = value; }
    }
}

De cette façon, vous n'avez pas à vous soucier des validations côté client/serveur, le framework se comportera comme il est censé le faire. De plus, si vous définissez un [Display] sur la classe de base, vous n'avez pas besoin de le redéfinir dans votre classe de base. UpdateModel .

Et vous pouvez toujours utiliser ces classes de la même manière :

[HttpPost]
public ActionResult Update(UpdateModel model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertModel model)
{
    ...
}

0 votes

Je préfère cette approche, surtout si vous avez une longue liste d'attributs de validation. Dans votre exemple, vous pouvez ajouter d'autres attributs dans la classe de base pour que l'avantage soit plus apparent. Le seul inconvénient que je vois est qu'il n'y a aucun moyen pour les propriétés héritées de remplacer les attributs. Par exemple, si vous avez une propriété [Required] sur la classe de base, la propriété héritée est forcée d'être également [Required], à moins que vous n'ayez un attribut [Optional] personnalisé.

0 votes

J'ai pensé à quelque chose comme ça aussi, mais j'ai un viewModel qui a un objet 'Project' qui a plusieurs attributs et je veux seulement qu'un de ces attributs soit validé dans certaines circonstances. Je ne pense pas que je puisse simplement remplacer un attribut d'un objet, n'est-ce pas ?

0 votes

Vous ne pouvez pas remplacer l'attribut. La classe de base ne doit contenir que des attributs communs à toutes les sous-classes. Ensuite, vos sous-classes doivent définir les attributs dont elles ont besoin.

18voto

int-i Points 31

Côté client Pour désactiver la validation d'un formulaire, plusieurs options basées sur mes recherches sont données ci-dessous. J'espère que l'une d'entre elles vous conviendra.

Option 1

Je préfère cela, et cela fonctionne parfaitement pour moi.

(function ($) {
    $.fn.turnOffValidation = function (form) {
        var settings = form.validate().settings;

        for (var ruleIndex in settings.rules) {
            delete settings.rules[ruleIndex];
        }
    };
})(jQuery); 

et l'invoquer comme

$('#btn').click(function () {
    $(this).turnOffValidation(jQuery('#myForm'));
});

Option 2

$('your selector here').data('val', false);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");

Option 3

var settings = $.data($('#myForm').get(0), 'validator').settings;
settings.ignore = ".input";

Option 4

 $("form").get(0).submit();
 jQuery('#createForm').unbind('submit').submit();

Option 5

$('input selector').each(function () {
    $(this).rules('remove');
});

Côté serveur

Créez un attribut et marquez votre méthode d'action avec cet attribut. Personnalisez cela pour l'adapter à vos besoins spécifiques.

[AttributeUsage(AttributeTargets.All)]
public class IgnoreValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;

        foreach (var modelValue in modelState.Values)
        {
            modelValue.Errors.Clear();
        }
    }
}

Une meilleure approche a été décrite ici Activer/désactiver dynamiquement la validation côté serveur de mvc

1 votes

$('input selector').each(function () { $(this).rules('remove');}) ; m'a aidé

0 votes

La question portait spécifiquement sur la suppression de la validation des champs obligatoires, et non sur la suppression de toute validation. Votre réponse concerne la suppression de toute validation.

14voto

nttakr Points 964

Personnellement, j'aurais tendance à utiliser l'approche présentée par Darin Dimitrov dans sa solution. Cela vous libère pour pouvoir utiliser l'approche d'annotation de données avec validation ET avoir des attributs de données séparés sur chaque ViewModel correspondant à la tâche à accomplir. Pour minimiser la quantité de travail nécessaire à la copie entre le modèle et le modèle de vue, vous devriez vous tourner vers AutoMapper ou ValueInjecter . Les deux ont leurs points forts individuels, alors vérifiez-les tous les deux.

Une autre approche possible pour vous serait de dériver votre viewmodel ou votre modèle de IValidatableObject. Cela vous donne la possibilité d'implémenter une fonction Validate. Dans la fonction Valider, vous pouvez retourner soit une liste d'éléments ValidationResult, soit émettre un retour de rendement pour chaque problème détecté lors de la validation.

Le ValidationResult se compose d'un message d'erreur et d'une liste de chaînes de caractères contenant les noms des champs. Les messages d'erreur seront affichés à un endroit proche du ou des champs de saisie.

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
  if( NumberField < 0 )
  {
    yield return new ValidationResult( 
        "Don't input a negative number", 
        new[] { "NumberField" } );
  }

  if( NumberField > 100 )
  {
    yield return new ValidationResult( 
        "Don't input a number > 100", 
        new[] { "NumberField" } );
  }

  yield break;
}

0 votes

Peut-on l'accrocher du côté client ?

0 votes

La validation côté client est généralement effectuée pour des champs individuels uniquement, en effectuant un retour interactif de la validation champ par champ, pour la commodité de l'utilisateur. Étant donné que l'étape de validation de l'objet implique généralement une validation dépendante (plusieurs champs et/ou conditions qui sont externes à l'objet lui-même), elle ne peut pas nécessairement être effectuée côté client, même si vous pouvez compiler le code en JavaScript. Si la validation complexe/dépendante côté client apporte une valeur ajoutée dans votre cas, vous devrez utiliser la fonction onsubmit-callback et dupliquer la logique de validation côté client.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X