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.