我正在使用JSF 2.1 + Primefaces 5.1开发一个Web应用程序。我有一个带行版的数据表,每行有2 inputText
,2 selectOneMenu
和1 selectBooleanCheckbox
。我想在点击检查图标时执行一些业务逻辑验证:它将验证2 selectOneMenu
的值。为此,我创建了一个与第二个selectOneMenu
关联的自定义验证器,用于验证这两个值:
<p:dataTable id="users_table_id" var="user" value="#{usersBean.users}" rowKey="#{user.id}" paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" emptyMessage="#{msgs.no_records}" sortBy="#{user.id}" sortOrder="ascending" rows="15" editable="true">
<f:facet name="header">
#{msgs.users}
</f:facet>
<p:ajax event="rowEdit" listener="#{usersBean.onRowEdit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditInit" listener="#{usersBean.onRowEditInit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditCancel" listener="#{usersBean.onRowEditCancel}" update=":users_form_id:growl"/>
<p:column headerText="#{msgs.id}" sortBy="#{user.id}" styleClass="centered-column">
#{user.id}
</p:column>
<p:column headerText="#{msgs.description}" sortBy="#{user.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.description}</f:facet>
<f:facet name="input"><p:inputText value="#{user.description}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.password}" sortBy="#{user.password}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.password}</f:facet>
<f:facet name="input"><p:inputText value="#{user.password}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.sending_system}" sortBy="#{user.playerIn.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerIn.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu binding="#{userPlayerInComponent}" styleClass="editable-cell" id="users_table_sending_system_id" value="#{user.playerIn}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.receiving_system}" sortBy="#{user.playerOut.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerOut.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu styleClass="editable-cell" id="users_table_receiving_system_id" value="#{user.playerOut}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
<f:validator validatorId="userValidator"/>
<f:attribute name="userPlayerInComponent" value="#{userPlayerInComponent}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.active}" sortBy="#{user.active}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output"><p:selectBooleanCheckbox value="#{user.active}" disabled="true"/></f:facet>
<f:facet name="input"><p:selectBooleanCheckbox value="#{user.active}"/></f:facet>
</p:cellEditor>
</p:column>
<p:column styleClass="datatable-row-editor">
<p:rowEditor/>
</p:column>
<f:facet name="footer">
</f:facet>
</p:dataTable>
@FacesValidator("userValidator")
public class UserValidator implements Validator {
private static final Logger logger = LogManager.getLogger(UserValidator.class);
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
logger.entry(context, component, value);
if (value == null) {
return; // Let required="true" handle.
}
UIInput userPlayerInComponent = (UIInput)component.getAttributes().get("userPlayerInComponent");
if (!userPlayerInComponent.isValid()) {
return; // Already invalidated. Don't care about it then.
}
DtoPlayer playerIn = (DtoPlayer)userPlayerInComponent.getValue();
if (playerIn == null) {
return; // Let required="true" handle.
}
DtoPlayer playerOut = (DtoPlayer)value;
UsersBean usersBean = context.getApplication().evaluateExpressionGet(context, "#{usersBean}", UsersBean.class);
BigDecimal userId = usersBean.getUserEditingId();
logger.info(userId + " - " + playerIn.getDescription() + " - " + playerOut.getDescription());
for (DtoUser dtoUser : usersBean.getUsers()) {
if (!userId.equals(dtoUser.getId()) && dtoUser.getPlayerIn().equals(playerIn) && dtoUser.getPlayerOut().equals(playerOut)) {
logger.info("Invalidating...");
userPlayerInComponent.setValid(false);
FacesContext.getCurrentInstance().validationFailed();
throw new ValidatorException(new FacesMessage("BOOM!"));
}
}
logger.exit();
}
}
我原以为,当验证失败(并且抛出ValidatorException
)时,数据表行将保持编辑模式,并且两个selectOneMenu
以红色突出显示。但是会发生的是该行退出编辑模式,保留旧值。如果我再次编辑它,它会显示提交的值,无效的单元格会用红色标记。只要我尝试提交无效值,此行为就会继续。如果我关闭编辑模式,则会丢弃无效值,并且该行仅保留旧值(无论是在查看还是编辑模式下)。
我该如何解决这个问题?从Primefaces' showcase可以看出,当您尝试提交时,让我们说,年份单元格中包含alfabetic字符的字符串,该行保持编辑模式并突出显示。我想达到同样的行为。