我正在使用 JSF 2.1 + Primefaces 5.1 开发一个网络应用程序。我有一个带有行版本的数据表,每行有 2inputText
, 2 selectOneMenu
and 1 selectBooleanCheckbox
。我想在单击复选图标时执行一些业务逻辑验证:它将验证 2 的值selectOneMenu
s。为此,我创建了一个与第二个关联的自定义验证器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
s 以红色突出显示。但发生的情况是该行退出编辑模式,保留旧值。如果我再次编辑它,它会显示提交的值,并且无效的单元格会标记为红色。只要我尝试提交无效值,这种行为就会持续下去。如果我关闭编辑模式,无效值将被丢弃,并且该行仅保留旧值(无论是在查看模式还是编辑模式下)。
我该如何解决这个问题?来自Primefaces 的展示 http://www.primefaces.org/showcase/ui/data/datatable/edit.xhtml,可以看到,当您尝试提交(比方说)年份单元格中包含字母字符的字符串时,该行将保持编辑模式并突出显示。我想实现同样的行为。