2013-11-18 9 views
2

У меня возникли проблемы с проверкой DateFields. В моем приложении у меня есть таблица с свойствами DateField, которую пользователи должны иметь возможность редактировать, нажав кнопку редактирования. У меня также есть кнопка OK, которая фиксирует поля и кнопку отмены, которая отбрасывает их.Как правильно проверить DateField в Vaadin?

Вот что я хочу достичь (конечно, есть некоторые аккуратные правила, которые нужно выполнять):

  • Во-первых, сроки могут быть изменены только на текущий день до 9999 -12-31.
  • Во-вторых, я предпочитаю, чтобы валидация была динамической (как у вас)
  • Исходные даты (даты, которые уже находятся в таблице при переходе в режим редактирования) могут быть любой датой, и вы должны иметь возможность совершайте их так, как они есть, даже если они в прошлом.
  • Если вы изменили дату на недопустимую дату (вы все равно можете сделать это «вручную», то есть непосредственно в поле, а не в подборщике даты) или ввести недопустимый символ в DateField, должен отображаться значок ошибки с сообщение, не позволяющее вам вносить изменения, пока вы не введете действительную дату.
  • Если вы изменили дату на недопустимую дату (отображается значок ошибки), а затем до допустимой даты, значок ошибки должен исчезнуть.

текущее поведение, что мне удалось реализовать делает следующее:

  • Позволяет «оригинальные даты» - OK
  • Позволяет изменять к действительной дате - OK
  • При переходе неверная дата (может быть выполнена «вручную», а не с помощью выбора даты) и нажмите клавишу ввода в поле, поле немедленно будет сброшено на исходную дату, но значок ошибки все еще отображается - НЕ ОК
  • При вводе недопустимого символа (можно сделать «вручную», не используя средство выбора даты), и нажмите клавишу ввода в поле, при вызове будет выбрано NPE, также отображается значок ошибки - НЕ ОК
  • При переходе на неверную дату и нажмите ввод в поле и обратно до действительной даты и нажмите клавишу ввода в поле, значок ошибки все еще там - НЕ ОК
  • При изменении на недопустимую дату и нажмите OK (т.е. commit()), поле сначала сбрасывается до исходной даты, и изменения (т. е. никаких изменений вообще не изменяются в поле) фиксируются - НЕ ОК

Теперь я попытался реализовать обертку, чтобы я мог слушать но у DateField нет удобных методов, таких как TextField (например, setTextChangeEventMode и setTextChangeTimeout). Я переопределяю valueChange, чтобы позаботиться о некоторых проблемах, но он кажется, что он вызван только при переходе на действительную дату, а не при переходе на недействительную дату (вы также должны нажимать клавишу ввода каждый раз, когда не используете средство выбора даты) ... вместо этого другая функция validate() вызывается в фоновом режиме, все время перезаписывая setValidationVisible().

Я даже попытался создать CustomDateRangeValidator, но выяснил, что это не очень поможет.

Пожалуйста, помогите мне получить это прямо, я пробовал так много вещей сейчас, и у меня заканчиваются варианты.

Вот мой метод createField:

createField(){ 
    // some more code up here... 

    if (propertyId.equals("Valid From")) { 
        dField.setImmediate(true); 

        dField.setRangeStart(new Date()); 
        dField.setRangeEnd(dateUtil.getDate(9999, 12, 31)); 
        dField.setDateOutOfRangeMessage("Date out of range!"); 

        @SuppressWarnings({ "unchecked", "rawtypes" }) 
        TableDataValidatingWrapper<TextField> wField = new TableDataValidatingWrapper(dField); 
        return wField; 
    } 

    // some more code down here... 
} 

... и вот моя обертка:

public class TableDataValidatingWrapper<T> extends CustomField<T> { 

    private static final long serialVersionUID = 1L; 
    protected Field<T> delegate; 

    public TableDataValidatingWrapper(final Field<T> delegate) { 
        this.delegate = delegate; 

        if (delegate instanceof DateField) { 
            final DateField dateField = (DateField) delegate; 

            dateField.setCaption(""); 
            dateField.setImmediate(true); 
            dateField.setInvalidAllowed(false); 
            dateField.setInvalidCommitted(true); 
            dateField.setValidationVisible(false); 
            dateField.addValueChangeListener(new ValueChangeListener() { 

                private static final long serialVersionUID = 1L; 

                @Override 
                public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { 
                    try { 
                        dateField.validate(); 
                        dateField.setValidationVisible(false); 
                    } catch (InvalidValueException ive) { 
                        //handle exception 
                    } catch (Exception e) { 
                        //handle exception 
                    } 
                } 
            }); 

        } 
    } 

//some other overridden methods here... 
} 
+0

вы получили какое-либо решение? – Visruth

ответ

0

Немного сложнее, но я надеюсь, что он работает (в Vaadin 7).
Я использую некоторые вспомогательные методы Apache и Joda-Time.
Возможно, потребуется какая-то настройка.

public class MyDateField extends CustomField<Date> { 

    private static final long serialVersionUID = 1L; 
    private static final DateTimeFormatter DTF; 

    static { 
     DTF = DateTimeFormat.forPattern("yyyy-MM-dd"); // set timezone if needed 
    } 

    private TextField tf = new TextField(); 
    private DateField df = new DateField(); 
    private Date original; 
    private Date minDay = new Date(); 
    private Date maxDay = new DateTime(9999, 12, 31, 23, 59).toDate(); 
    private boolean isInnerChange; 
    private Date convertedDate; 

    @Override 
    protected Component initContent() { 
     tf.setConverter(InnerConverter.INSTANCE); 
     tf.setTextChangeEventMode(TextChangeEventMode.EAGER); // or LAZY 
     tf.addTextChangeListener(new TextChangeListener() { 
      private static final long serialVersionUID = 1L; 

      @Override 
      public void textChange(TextChangeEvent event) { 
       int pos = tf.getCursorPosition(); 
       if (isValid(event.getText())) { 
        df.setComponentError(null); 
        isInnerChange = true; 
        df.setValue(convertedDate); 
       } else { 
        df.setComponentError(InnerErrorMessage.INSTANCE); 
       } 
       tf.setCursorPosition(pos); 
      } 
     }); 
     df.setStyleName("truncated-date-field"); 
     df.addValueChangeListener(new Property.ValueChangeListener() { 
      private static final long serialVersionUID = 1L; 

      @Override 
      public void valueChange(Property.ValueChangeEvent event) { 
       if (!isInnerChange) { 
        Date d = df.getValue(); 
        df.setComponentError(isValid(d) ? null : InnerErrorMessage.INSTANCE); 
        tf.setValue(d == null ? "" : DTF.print(d.getTime())); 
       } 
       isInnerChange = false; 
      } 
     }); 
     return new HorizontalLayout(tf, df); 
    } 

    @Override 
    public void setPropertyDataSource(@SuppressWarnings("rawtypes") Property newDS) { 
     tf.setPropertyDataSource(newDS); 
     if (newDS != null && getType().isAssignableFrom(newDS.getType())) { 
      original = (Date) newDS.getValue(); 
     } else { 
      original = null; 
     } 
     df.setValue(original); 
    } 

    @Override 
    public void commit() throws SourceException, InvalidValueException { 
     ErrorMessage em = df.getComponentError(); 
     if (em != null) { 
      throw new InvalidValueException(em.getFormattedHtmlMessage()); 
     } 
     tf.commit(); 
    } 

    @Override 
    public Class<? extends Date> getType() { 
     return Date.class; 
    } 

    private boolean isValid(String s) { 
     s = StringUtils.trimToNull(s); 
     if (s == null) { 
      convertedDate = null; 
      return true; 
     } 
     try { 
      return isValid(DTF.parseDateTime(s).toDate()); 
     } catch (Exception e) { 
      return false; 
     } 
    } 

    private boolean isValid(Date d) { 
     if (d == null || DateUtils.truncatedEquals(original, d, Calendar.DAY_OF_MONTH)) { 
      convertedDate = d; 
      return true; 
     } 
     if (DateUtils.truncatedCompareTo(minDay, d, Calendar.DAY_OF_MONTH) <= 0 
       && DateUtils.truncatedCompareTo(maxDay, d, Calendar.DAY_OF_MONTH) >= 0) { 
      convertedDate = d; 
      return true; 
     } 
     return false; 
    } 

    // other methods if needed 

    private static class InnerErrorMessage implements ErrorMessage { 

     private static final long serialVersionUID = 1L; 
     private static final InnerErrorMessage INSTANCE = new InnerErrorMessage(); 

     @Override 
     public String getFormattedHtmlMessage() { 
      return "Invalid date!"; 
     } 

     @Override 
     public ErrorLevel getErrorLevel() { 
      return ErrorLevel.ERROR; 
     } 

     private Object readResolve() { 
      return INSTANCE; // preserves singleton property 
     } 

    } 

    private static class InnerConverter implements Converter<String, Date> { 

     private static final long serialVersionUID = 1L; 
     private static final InnerConverter INSTANCE = new InnerConverter(); 

     @Override 
     public Date convertToModel(String value, Class<? extends Date> targetType, Locale locale) 
       throws ConversionException { 
      String s = StringUtils.trimToNull(value); 
      if (s == null) { 
       return null; 
      } 
      try { 
       return DTF.parseDateTime(s).toDate(); 
      } catch (Exception e) { 
       throw new ConversionException(e); 
      } 
     } 

     @Override 
     public String convertToPresentation(Date value, Class<? extends String> targetType, Locale locale) 
       throws ConversionException { 
      return value == null ? "" : DTF.print(value.getTime()); 
     } 

     @Override 
     public Class<Date> getModelType() { 
      return Date.class; 
     } 

     @Override 
     public Class<String> getPresentationType() { 
      return String.class; 
     } 

     private Object readResolve() { 
      return INSTANCE; // preserves singleton property 
     } 

    } 

} 

В вашем styles.css:

.truncated-date-field > input.v-datefield-textfield { 
    display: none; 
}