12 votes

JSF comment désactiver temporairement les validateurs pour enregistrer un brouillon

J'ai un formulaire assez complexe avec de nombreux champs et validateurs. Pour l'utilisateur, cela prend beaucoup de temps (même plus d'une heure) pour le remplir, donc ils aimeraient pouvoir enregistrer les données de brouillon, même si cela enfreint des règles telles que des champs obligatoires non saisis.

Je pense que ce problème est commun à de nombreuses applications web, mais je ne trouve aucun schéma bien reconnu sur la manière dont cela devrait être implémenté. Pouvez-vous s'il vous plaît me conseiller sur la façon d'y parvenir?

Pour l'instant, je vois les options suivantes:

  1. l'utilisation de immediate=true sur le bouton "Enregistrer le brouillon" ne fonctionne pas, car les données de l'interface utilisateur ne seraient pas stockées dans le bean, je ne pourrais donc pas y accéder. Techniquement, je pourrais trouver les données dans l'arborescence des composants d'interface utilisateur, mais il ne semble pas être une bonne idée de la traverser.
  2. supprimer toutes les validations des champs de la page et valider les données de manière programmatique dans le gestionnaire d'événements défini pour le formulaire. Encore une fois, ce n'est pas une bonne idée, le formulaire est vraiment complexe, il y a beaucoup de champs donc la validation mise en œuvre de cette manière serait très confuse.
  3. implémenter mes propres validateurs, qui seraient contrôlés par un attribut de requête, qui serait défini pour une soumission de formulaire standard (avec une validation complète attendue) et serait désactivé pour une soumission "sauvegarde en tant que brouillon" (où la validation doit être ignorée). Encore une fois, ce n'est pas une bonne solution, je devrais fournir mes propres wrappers pour tous les validateurs que j'utilise.

Mais comme vous le voyez, aucune n'est vraiment raisonnable. Y a-t-il vraiment aucune solution simple à ce problème?

8voto

BalusC Points 498232

En effet, ce n'est pas si facile. La validation est assez étroitement couplée dans le cycle de vie de JSF.

Je choisirais personnellement l'option 1. Certes, c'est du travail sale, mais vous pouvez simplement le cacher dans une classe utilitaire ou autre. Il suffit de récupérer le en question à partir de la racine de la vue, d'itérer sur ses enfants de manière récursive, en testant si component instanceof EditableValueHolder est vrai, de stocker la paire id-valeur trouvée dans une sorte de Map et enfin de la persister.

Comme quatrième alternative, vous pourriez sauvegarder toutes les données de manière indépendante en utilisant les pouvoirs ajaxiques. jQuery est utile à cet égard.

$.post('/savedraft', $('#formid').serialize());

Cela requiert uniquement la prise en charge de Javascript côté client.


Mise à jour: la bibliothèque utilitaire JSF OmniFaces possède un taghandler pour l'objectif précis. Ce n'était en effet pas une solution simple car elle nécessite également un personnalisé. Elle fait son travail en fournissant une instance personnalisée de FacesContext pendant les phases de validation et de mise à jour des valeurs du modèle, qui ne fait rien dans les méthodes validationFailed() et renderResponse(). Ainsi, les composants restent invalidés et les messages restent attachés, mais le processus se poursuivra dans les phases de mise à jour des valeurs du modèle et d'invocation de l'application.

1voto

ForguesR Points 2858

J'ai eu le même problème et je n'aimais pas l'idée de sauter toutes les validations. Après beaucoup de réflexion, j'ai finalement décidé de vouloir juste sauter la validation des champs requis. La logique derrière cela est que l'utilisateur doit remplir un champ correctement ou ne pas le remplir du tout. Ceci est très important pour moi car tout finit par être enregistré dans la base de données et, bien sûr, je ne veux pas déborder un champ de base de données ou finir par enregistrer une valeur String dans un champ de base de données INT par exemple.

Dans mon expérience, sauter les champs requis permet une marge de manoeuvre suffisante pour enregistrer un brouillon. Pour y parvenir, j'ai fini par écrire un requiredWarnValidator qui affiche un seul message d'avertissement.

public void validate(FacesContext context, UIComponent component, Object value)
    throws ValidatorException {

  if (value == null) {
    FacesMessage message = new FacesMessage();
    message.setSeverity(FacesMessage.SEVERITY_WARN);
    message.setSummary("Ce champ est requis.");
    context.addMessage(component.getClientId(), message);
    context.validationFailed();
  }
}

Dans ce validateur, je ne lance pas d'exception ValidatorException() car je veux passer la phase de validation mais j'appelle validationFailed() car je veux savoir si un champ requis n'est pas rempli.

J'ai un indicateur (completed) dans l'entité que j'utilise pour enregistrer mon formulaire. Lors de l'enregistrement du formulaire, je vérifie isValidationFailed().

  • si c'est true au moins un champ requis n'est pas rempli: je décoche l'indicateur completed. (c'est un brouillon)
  • si c'est false tout le formulaire est rempli : je coche l'indicateur completed. (ce n'est pas un brouillon)

Cela me permet également d'avoir un seul bouton "Enregistrer" au lieu de deux boutons ("Enregistrer" et "Enregistrer comme brouillon").

Notes et pièges connus :

  • Si vous enregistrez votre brouillon dans la base de données, assurez-vous qu'il n'y a pas de contraintes NOT NULL.
  • Lors de l'utilisation de convertisseurs et de validateurs, assurez-vous qu'ils peuvent gérer les valeurs NULL.
  • Vous perdrez l'astérisque des champs requis dans le outputLabel pour vos champs.

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