O valueChangeListenerserá chamado apenas quando o formulário for enviado e o valor enviado for diferente do valor inicial. Portanto, não é invocado quando apenas o changeevento HTML DOM é disparado. Se desejar enviar o formulário durante o changeevento HTML DOM , será necessário adicionar outro <f:ajax/>sem ouvinte (!) Ao componente de entrada. Isso causará um envio de formulário que processa apenas o componente atual (como em execute="@this").
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
Ao usar em <f:ajax listener>vez de valueChangeListener, por padrão já seria executado durante o changeevento HTML DOM . Dentro dos UICommandcomponentes e dos componentes de entrada que representam uma caixa de seleção ou botão de opção, ele seria executado por padrão apenas durante o clickevento HTML DOM .
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Outra grande diferença é que o valueChangeListenermétodo é invocado durante o final da PROCESS_VALIDATIONSfase. Nesse momento, o valor enviado ainda não foi atualizado no modelo. Portanto, você não pode obtê-lo apenas acessando a propriedade do bean que está vinculada ao componente de entrada value. Você precisa passar por isso ValueChangeEvent#getNewValue(). O valor antigo também está disponível por ValueChangeEvent#getOldValue().
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
O <f:ajax listener>método é invocado durante a INVOKE_APPLICATIONfase. Nesse momento, o valor enviado já está atualizado no modelo. Você pode obtê-lo acessando diretamente a propriedade do bean que está vinculada ao componente de entrada value.
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Além disso, se você precisar atualizar outra propriedade com base no valor enviado, haverá falha ao usar, valueChangeListenerpois a propriedade atualizada pode ser substituída pelo valor enviado durante a UPDATE_MODEL_VALUESfase subsequente . É exatamente por isso que você vê em aplicativos / tutoriais / recursos antigos do JSF 1.x que um valueChangeListenerestá em tal construção sendo usado em combinação immediate="true"e FacesContext#renderResponse()para evitar que isso aconteça. Afinal, usando ovalueChangeListener para executar ações de negócios sempre foi, na verdade, um hack / solução alternativa.
Resumido: Use o valueChangeListenerapenas se precisar interceptar a própria mudança de valor real. Ou seja, você está realmente interessado em tanto o velho eo novo valor (por exemplo, para registrá-los).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Use <f:ajax listener>apenas se precisar executar uma ação comercial no valor recém-alterado. Ou seja, você está realmente interessado apenas no novo valor (por exemplo, para preencher um segundo menu suspenso).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
Se você realmente também estiver interessado no valor antigo ao executar uma ação de negócios, volte valueChangeListener, mas coloque-o na INVOKE_APPLICATIONfase.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value)); // true
// ...
}
logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );. Parece que você poderia usar os valores antigos e novos obtidos dessa maneira para fazer a lógica de negócios diretamente no setter, bem como um registro simples, mas não sei se isso causaria efeitos colaterais ...