JSF должен сохранять состояние дерева компонентов, как определено жизненным циклом платформы.
Однако, в зависимости от того, как функционирует ваша страница JSF, вы можете выбрать, например, только частичную обработку страницы всякий раз, когда событие происходит. В этом случае только обработанные компоненты сохранят свое состояние.
Давайте рассмотрим ваш пример использования и сначала определим представление:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions">
<h:head>
<title>SelectOneMenu Validation</title>
</h:head>
<h:body>
<h:form>
<o:validateMultiple id="validateMatch" components="home away"
validator="#{selectBackingBean.onValidateMatch}"
message="The combination already exists or is invalid!" />
<p:dataList value="#{selectBackingBean.matches}" var="match">
<f:facet name="header">Home / Away</f:facet>
#{match.home} vs #{match.away}
</p:dataList>
<br/><br/>
<p:selectOneMenu id="home" label="Please select home..." value="#{selectBackingBean.selectedHome}">
<f:selectItems value="#{selectBackingBean.teams}" var="team"
itemValue="#{team}" itemLabel="#{team}" />
</p:selectOneMenu>
<p:selectOneMenu id="away" label="Please select away..." value="#{selectBackingBean.selectedAway}">
<f:selectItems value="#{selectBackingBean.teams}" var="team"
itemValue="#{team}" itemLabel="#{team}" />
</p:selectOneMenu>
<h:panelGroup>
<br/>
<h:message for="validateMatch" />
<h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:panelGroup>
<br/><br/>
<p:commandButton value="Save" action="#{selectBackingBean.onSave}" update="@form" />
</h:form>
</h:body>
</html>
Давайте также определим базовый компонент, содержащий представление состояние и модель:
@Data
@Named
@ViewScoped
public class SelectBackingBean implements Serializable {
private List<String> teams;
private List<Match> matches;
private String selectedHome;
private String selectedAway;
@Data
@AllArgsConstructor
public class Match {
private String home;
private String away;
}
@PostConstruct
private void init() {
teams = Arrays.asList("Malmö FF", "GAIS", "IFK Göteborg", "AIK");
matches = new ArrayList<>(Arrays.asList(new Match("Malmö FF", "AIK")));
}
public boolean onValidateMatch(FacesContext context, List<UIInput> components,
List<String> values) {
return values.get(0) != values.get(1) && !matches.contains(new Match(values.get(0), values.get(1)));
}
public void onSave() {
matches.add(new Match(selectedHome, selectedAway));
}
}
Если мы сейчас запустим это, мы получим следующие результаты:
Если мы продолжим и, в конечном итоге, столкнувшись с ошибкой проверки, мы получаем следующее:
Обратите внимание, что он постоянно сохраняет состояние всех компонентов. В OmniFaces и JSF есть компоненты, которые позволяют вам контролировать состояние выбранных частей дерева компонентов, чтобы уйти от этого поведения.
Я предполагаю, что в вашем коде что-то происходит или вы каким-то образом сбрасывать значения базовых компонентов, связанных с компонентами.