Ajax for valueChangeListener
Asked Answered
A

5

11

I'm using the p:ajax listener to handle value change events (because valueChangeListener is launched on form submit):

<p:ajax event="change" listener="#{bean.onNameChanged}"/>

Handle method:

public void onNameChanged(final AjaxBehaviorEvent event)

The problem is, I can't find in AjaxBehaviorEvent nor its class hierarchy the place to read the old value of the input. Neither could I find hint in google, how to get the old value...

How to access the old value in the p:ajax onChange event?

Authorize answered 7/2, 2013 at 11:36 Comment(0)
G
20

The problem is, I can't find in AjaxBehaviorEvent nor its class hierarchy the place to read the old value of the input. Neither could I find hint in google, how to get the old value...

Use a valueChangeListener.


Unfortunatelly, valueChangeListener is invoked before p:ajax, so I don't have actual data from forms in that method, so in theory I could use valueChangeListener to remember the old value and then wait for p:ajax to process...

Queue the value change event to the invoke application phase.

public void valueChangeListenerMethod(ValueChangeEvent event) {
    if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
        event.queue();
        return;
    }

    // Do your original job here. 
    // It will only be invoked when current phase ID is INVOKE_APPLICATION.
}
Guibert answered 8/2, 2013 at 11:20 Comment(4)
+1, Someone should do "BalusC IS AWESOME" video (just like "PEOPLE ARE AWESOME" videos)Scend
Bauke you're amazing guy :D You just saved me hours of head scratching.Shieh
As usual BalusC has solved my problem for me years before I had it.Neb
@BalusC, thank you for this answer, 'JSF is religion-BalusC is god.'Grosberg
B
7

The ValueChangeListener should work this way:

The view:

<h:form>
  <h:inputText value="#{sessionBean.hello}" 
               valueChangeListener="#{sessionBean.valueChangeListener}">
    <p:ajax/>
  </h:inputText>
</h:form>

The bean:

public void valueChangeListener(ValueChangeEvent e) {
  System.out.println("valueChangeListener invoked:" 
                      + " OLD: " + e.getOldValue() 
                      + " NEW: " + e.getNewValue());
}

The above code will print if I change the text field from "hello" to "world":

valueChangeListener invoked: OLD: hello NEW: world

Benoite answered 8/2, 2013 at 10:59 Comment(2)
do you know how to made also the bean changes visible to the server code? with p:ajax I have the process option, to send the UI control's content, with that way they are in state from last submit...Authorize
@lechlukasz: Take a look at BalusC's answer.Benoite
R
3

You could try the following:

  1. Implement the value change event in your bean

     public void processValueChange(ValueChangeEvent e){
     //foo the bar
     }
    
  2. Define a valueChangeListener on your selection component

     <p:selectOneMenu value="#{yourBean.value}" onchange="submit()" valueChangeListener="{#yourBean.processValueChange}">
    

    The key piece there is the submit() bit that processes the enclosing form on change of the value. You can then getNewValue() and getOldValue() as necessary.

EDIT: Now that I think about it, I see no reason why you cannot leave your setup as-is and simply define the valueChangeListener. It should still be processed during the change event in the <p:ajax/>, in fact, it will be processed before the listener for the ajax event itself.

Refined answered 8/2, 2013 at 5:18 Comment(3)
No, submit can't be done (because of validation) and the changes must be visible to other components after changing the field, so it's not a solution)Authorize
@lechlukasz: You can do a partial submit as stated in the "EDIT"-part of kolossus answer. Then the valueChangeListener will be invoked and you can access the old and the new value. All other form elements will not be evaluated/processed (unless you put it in the execute attribute of the ajax call.)Benoite
Unfortunatelly, valueChangeListener is invoked before p:ajax, so I don't have actual data from forms in that method, so in theory I could use valueChangeListener to remember the old value and then wait for p:ajax to process...Authorize
T
0

you can use this:

public void onNameChanged(AjaxBehaviorEvent event)
 {
    String myVal = (String) ((UIOutput) event.getSource()).getValue();
    System.out.println("myVal: " + myVal);
 }
Thorium answered 31/12, 2014 at 9:39 Comment(1)
OP is interested in "old value" as it was before update model values phase has taken place. The ajax listener, however, runs after update model values phase. See the currently accepted answer for the proper approach.Guibert
B
-1

Workaround is possible (tested with Primefaces 10):

<p:inputText id="name" value="bean.name">
     <p:ajax event="valueChange" update="name"
             listener="#{bean.onNameChanged}"
             onstart="cfg.ext={params:[{name:'oldValue', value:'#{bean.name}'}]};"/>
</p:inputText>

update="name" is important, to get each time the new value into the javascript event handler.

Bean Method:

public void onNameChanged(final AjaxBehaviorEvent event) {
    String oldValue = getFacesContext().getExternalContext().getRequestParameterMap()
                      .get("oldValue");
    //Do with oldValue, whatever you want
}
Blue answered 24/1, 2022 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.