O valueChangeListener
será chamado apenas quando o formulário for enviado e o valor enviado for diferente do valor inicial. Portanto, não é invocado quando apenas o change
evento HTML DOM é disparado. Se desejar enviar o formulário durante o change
evento 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 change
evento HTML DOM . Dentro dos UICommand
componentes 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 click
evento HTML DOM .
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Outra grande diferença é que o valueChangeListener
método é invocado durante o final da PROCESS_VALIDATIONS
fase. 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_APPLICATION
fase. 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, valueChangeListener
pois a propriedade atualizada pode ser substituída pelo valor enviado durante a UPDATE_MODEL_VALUES
fase subsequente . É exatamente por isso que você vê em aplicativos / tutoriais / recursos antigos do JSF 1.x que um valueChangeListener
está 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 valueChangeListener
apenas 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_APPLICATION
fase.
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 ...