我在验证DateFields时遇到了一些麻烦。 在我的应用程序中,我有一个具有DateField属性的表,用户应该可以通过按下编辑按钮来编辑它们。我还有一个提交字段的OK按钮和一个丢弃它们的取消按钮。
这就是我想要实现的目标(当然,必须遵循一些简洁的规则):
我设法实施的当前行为执行以下操作:
现在,我尝试实现一个包装器,以便我可以监听值的更改,但是DateField没有像TextField那样方便的方法(例如setTextChangeEventMode和setTextChangeTimeout)。我覆盖了valueChange来处理一些问题,但是只有在你改为有效日期时才会调用它,而不是当你改为无效日期时(每次不使用日期选择器时你也必须按Enter键) ...而是在后台调用另一个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 :(得分:0)
有点复杂,但我希望它有效(在Vaadin 7中) 我使用了一些Apache Commons和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;
}