Quando utilizzare valueChangeListener of: ajax listener?


87

Qual è la differenza tra le seguenti due parti di codice per quanto riguarda il listenerposizionamento?

<h:selectOneMenu ...>
    <f:selectItems ... />
    <f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>

e

<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
    <f:selectItems ... />
</h:selectOneMenu>

Risposte:


182

Il valueChangeListenerverrà invocato solo quando il modulo viene inviato e il valore inviato è diverso dal valore iniziale. Non viene quindi richiamato quando viene attivato solo l' changeevento HTML DOM . Se desideri inviare il modulo durante l' changeevento HTML DOM , devi aggiungerne un altro <f:ajax/>senza un listener (!) Al componente di input. Provocherà un invio del modulo che elabora solo il componente corrente (come in execute="@this").

<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
    <f:selectItems ... />
    <f:ajax />
</h:selectOneMenu>

Quando si utilizza <f:ajax listener>invece di valueChangeListener, viene eseguito per impostazione predefinita già durante l' changeevento HTML DOM . All'interno di UICommandcomponenti e componenti di input che rappresentano una casella di controllo o un pulsante di opzione, verrà eseguito per impostazione predefinita solo durante l' clickevento HTML DOM .

<h:selectOneMenu value="#{bean.value}">
    <f:selectItems ... />
    <f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>

Un'altra importante differenza è che il valueChangeListenermetodo viene richiamato durante la fine della PROCESS_VALIDATIONSfase. In quel momento, il valore inviato non è stato ancora aggiornato nel modello. Quindi non puoi ottenerlo accedendo semplicemente alla proprietà bean che è associata a quella del componente di input value. Devi farcela ValueChangeEvent#getNewValue(). Il vecchio valore è tra l'altro disponibile anche da ValueChangeEvent#getOldValue().

public void changeListener(ValueChangeEvent event) {
    Object oldValue = event.getOldValue();
    Object newValue = event.getNewValue();
    // ...
}

Il <f:ajax listener>metodo viene richiamato durante la INVOKE_APPLICATIONfase. In quel momento, il valore inviato è già stato aggiornato nel modello. Puoi ottenerlo accedendo direttamente alla proprietà bean che è associata a quella del componente di input value.

private Object value; // +getter+setter.

public void ajaxListener(AjaxBehaviorEvent event) {
    System.out.println(value); // Look, (new) value is already set.
}

Inoltre, se fosse necessario aggiornare un'altra proprietà in base al valore inviato, non funzionerebbe quando si utilizza valueChangeListenerpoiché la proprietà aggiornata può essere sovrascritta dal valore inviato durante la UPDATE_MODEL_VALUESfase successiva . Questo è esattamente il motivo per cui nelle vecchie applicazioni / tutorial / risorse JSF 1.x si vede che a valueChangeListenerè stato utilizzato in tale costrutto in combinazione con immediate="true"e FacesContext#renderResponse()per evitare che ciò accada. Dopotutto, l'utilizzo di valueChangeListenerper eseguire azioni aziendali è sempre stato un trucco / soluzione alternativa.

Riepilogo: utilizzare valueChangeListenersolo se è necessario intercettare la variazione del valore effettivo stesso. Cioè sei effettivamente interessato sia al vecchio che al nuovo valore (ad esempio per registrarli).

public void changeListener(ValueChangeEvent event) {
    changeLogger.log(event.getOldValue(), event.getNewValue());
}

Utilizzare <f:ajax listener>solo se è necessario eseguire un'azione commerciale sul valore appena modificato. Cioè in realtà sei interessato solo al nuovo valore (ad esempio per popolare un secondo menu a discesa).

public void ajaxListener(AjaxBehaviorEvent event) {
    selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}

Se in realtà sei interessato anche al vecchio valore durante l'esecuzione di un'azione aziendale, ripiega su valueChangeListener, ma mettilo in coda alla 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
    // ...
}

@BalusC, c'è una ragione per non ottenere il vecchio valore dall'oggetto di supporto nel setter prima di impostarlo sul nuovo valore che viene passato? Qualcosa di simile a questo: logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );. Sembra che potresti usare i valori vecchi e nuovi ottenuti in quel modo per fare la logica di business direttamente nel setter così come il semplice logging, ma non so se questo causerebbe effetti collaterali ...
Lucas

Risposta perfetta e completa! Grazie per avere condiviso le tue conoscenze!
hbobenicio

@BalusC è possibile ottenere anche il valore modificato tramite AjaxBehaviorEvent? Ho <h: selectManyListbox che è incatenato ad altri componenti e mi piacerebbe usare il modificato (aggiunto / rimosso) per eseguire alcune azioni
Paullo


Grazie @BalusC Ma non credo che ValueChangeListener si adatterà al mio caso perché ho alcuni valori di esecuzione e rendering come mostrato <f: ajax event = "valueChange" render = "tests" execute = "@ this" listener = "# {testController. processTimeTable} "/>
Paullo

9

per il primo frammento (attributo listener ajax):

L'attributo "listener" di un tag ajax è un metodo che viene chiamato sul lato server ogni volta che la funzione ajax viene eseguita sul lato client. Ad esempio, è possibile utilizzare questo attributo per specificare una funzione lato server da chiamare ogni volta che l'utente preme un tasto

ma il secondo frammento (valueChangeListener):

ValueChangeListener verrà chiamato solo quando il modulo viene inviato, non quando il valore dell'input viene modificato

* potresti visualizzare questa utile risposta

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.