2017-10-06 3 views
0

Je:Comment déterminer si un DateField est valable dans Vaadin 8

DateField dateField = new DateField("Date"); 
Button submitButton = new Button("Submit"); 
submitButton.addClickListener(click -> handleClickListener()); 

où dans handleClickListener() Je veux éviter un soumettre s'il y a une erreur de validation dans le DateField. Je sais que je peux utiliser un classeur, puis binder.validate() mais ce formulaire n'a pas d'objet de support et je veux juste un formulaire simple. Comment puis-je faire quelque chose comme:

if(!dateField.isValid()) 
    // no further processing 
else 
    // process 

Je ne peux pas trouver un code dans la DateField qui permet de vérifier si l'entrée de la valeur est valide. Apparemment in Vaadin 7 you could !dateField.validate() which would throw an exception mais cela ne semble plus être le cas ...

Je sais aussi qu'il est possible de faire dateField.isEmpty() ou de tester null mais cela ne fonctionne pas car une valeur n'est PAS requise. En d'autres termes, il peut être vide, ou si vous entrez une valeur, il doit s'agir d'une entrée valide.

+0

Comment utiliser 'Binder' (https://vaadin.com/api/8.0.1/com/vaadin/data/Binder.html)? 'Binder' vient avec des méthodes comme' validate() 'et' isValid() '. – Thibstars

+0

Parfois, Binder ne fonctionne pas. Par exemple, mon formulaire n'a peut-être pas de POJO, etc. derrière lui, peut-être que j'utilise simplement le formulaire pour faire un calcul rapide sur une étiquette et que je ne veux pas le sauvegarder avec quoi que ce soit. –

Répondre

3

Cela a été demandé plusieurs fois, et pour autant que je sache, il n'est pas possible d'ajouter des validateurs sans le classeur. Vous pouvez vérifier this answer pour une description complète de la fonctionnalité et de la résonance.

Il y a aussi des discussions sur les Vaadin forum et github, et les 2 suggestions principales utilisent un classeur, ou un écouteur de changement de valeur où vous appelez manuellement un validateur. Cependant, cette dernière solution ne semble pas fonctionner et je suppose que c'est parce qu'un événement de changement de valeur n'est déclenché que lorsque la valeur réelle change, ce qui ne se produit probablement pas lorsque vous tapez quelque chose de non valide.

Le latest suggestion on github demande une méthode binder.noBind() pour faciliter ces cas, mais jusqu'à ce que cela soit implémenté, vous pouvez utiliser quelque chose de similaire à l'exemple de code ci-dessous. J'ai aussi haï l'idée d'utiliser un champ pour lier la valeur, donc je suis allé avec un pas setter & pas getter concept:

public class DateFieldWithValidator extends VerticalLayout { 

    public DateFieldWithValidator() { 
     // date field with binder 
     Binder<LocalDate> binder = new Binder<>(); 
     DateField dateField = new DateField("Date"); 
     binder.forField(dateField) 
       .asRequired("Please select a date") 
       .bind(No.getter(), No.setter()); 

     // validity status 
     TextField validityField = new TextField("Status:", "N/A"); 
     validityField.setReadOnly(true); 
     validityField.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS); 
     validityField.setWidth("100%"); 

     // submit button 
     Button submitButton = new Button("Submit"); 
     submitButton.addClickListener(event -> { 
      BinderValidationStatus<LocalDate> status = binder.validate(); 
      if (status.isOk()) { 
       validityField.setValue("OK: " + dateField.getValue().toString()); 
      } else { 
       validityField.setValue("KO: " + status.getValidationErrors().stream().map(ValidationResult::getErrorMessage).collect(Collectors.joining(","))); 
      } 
     }); 

     addComponents(dateField, submitButton, validityField); 
    } 

    // convenience empty getter and setter implementation for better readability 
    public static class No { 
     public static <SOURCE, TARGET> ValueProvider<SOURCE, TARGET> getter() { 
      return source -> null; 
     } 

     public static <BEAN, FIELDVALUE> Setter<BEAN, FIELDVALUE> setter() { 
      return (bean, fieldValue) -> { 
       //no op 
      }; 
     } 
    } 
} 

Résultat:

date field validation with binder


Mise à jour ultérieure:

J'y ai réfléchi un peu plus, et si c'est acceptable, vous pouvez désactiver le bouton d'envoi si la valeur est nulle ou qu'une erreur d'analyse survient pour une valeur non valide. Cela peut être facilement mis en œuvre avec un ValueChangeListener et un ErrorHandler comme ci-dessous. Vous pouvez également enregistrer le message d'exception dans une variable et cliquer sur le bouton pour vérifier s'il existe un message d'erreur ou si la valeur est nulle, dans cet ordre, car si vous entrez une date non valide, la valeur du champ sera défini sur null.

public class DateFieldWithValidator extends VerticalLayout { 
    public DateFieldWithValidator() { 
     DateField dateField = new DateField("Date"); 
     Button submitButton = new Button("Submit"); 
     submitButton.setEnabled(false); 
     submitButton.addClickListener(event -> Notification.show("Selected date: " + dateField.getValue())); 
     dateField.setRequiredIndicatorVisible(true); 
     dateField.setErrorHandler(event -> submitButton.setEnabled(false)); 
     dateField.addValueChangeListener(event -> submitButton.setEnabled(event.getValue() != null)); 
     addComponents(dateField, submitButton); 
    } 
} 

Résultat:

vaadin date field validation

+0

C'est extrêmement proche de ce que j'ai fait. Vous créez essentiellement un faux POJO (ou quelque chose de similaire) pour lier avec le classeur et ensuite utiliser la validation du classeur lorsque vous cliquez sur le bouton Envoyer. –

+0

@StephaneGrenier Ouais, c'est à peu près l'idée, au moins pour l'instant .... – Morfic

+0

@StephaneGrenier Que diriez-vous de la deuxième approche? – Morfic

0

Même si vous dites que vous ne voulez pas utiliser un objet de soutien, je recommande l'utilisation de Binder de toute façon.La classe No fournie par @Morfic est excellente à mon avis (j'ai tendance à la réutiliser dans de nombreuses implémentations de validation).

donc ce que je ferais est d'ajouter un addStatusChangeListener sur votre classeur et activer/désactiver le bouton là:

binder.addStatusChangeListener(event -> { 
      if (event.hasValidationErrors()) { 
       submitButton.setEnabled(false); 
      } else { 
       submitButton.setEnabled(true); 
      } 
     }); 

l'instanciation de Omis l'objet Binder depuis @Morfic a fourni un bon exemple dans sa réponse déjà .

La raison pour laquelle je suggère l'utilisation de Binder est parce que Vaadin suggests to use it for validation, vous aurez pas besoin difficile de maintenir les auditeurs de changement de valeur et vous pourriez facilement étendre votre fixation avec de nouveaux Validator s si nécessaire plus tard. Peut-être que vous voudrez lier le champ à un objet après tout.