JSF 1.2: valueChangeListener event not returning newly selected value

icepax picture icepax · Dec 7, 2009 · Viewed 16.2k times · Source

I have this backing bean:

public class PageBean 
{
    private List<SelectItem> selectPages;
    private List<SelectItem> selectRowsPerPage;
    private String selectedPage;
    private String selectedRowsPerPage;
    private int pages = 0;

// getter methods
public boolean getRender()
{
    boolean rendered = pages > 0? true: false;
    return rendered;
}   

public List<SelectItem> getSelectPages() 
{
    int value = 0;

    selectPages = new ArrayList<SelectItem>();
    for (int i = 1; i < (pages + 1); i++) 
    {
        if (i > 1) { value = i * 10; }
        selectPages.add(new SelectItem(Integer.toString(value), Integer.toString(i)));
    }   

    return selectPages;
}

public String getSelectedPage()
{
    if (selectedPage == null) {
        selectedPage = "1";
    }

    return selectedPage;
}

// setter methods
public void setSelectPages(List<SelectItem> selectPages) {
    this.selectPages = selectPages;
}  

public void setSelectedPage(String selectedPage) {
    this.selectedPage = selectedPage;
}    

// action methods
public void changePage(ValueChangeEvent event)
{
    PhaseId phase = event.getPhaseId();

    if (phase.equals(PhaseId.INVOKE_APPLICATION)) {
        System.out.println((String) event.getNewValue());
        setSelectedPage((String) event.getNewValue());
        FacesContext.getCurrentInstance().renderResponse();
    } else {
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
        event.queue();
    } 
}    
}

And the h:selectOneMenu is:

<h:selectOneMenu id="page" value="#{pageBean.selectedPage}"
   valueChangeListener="#{pageBean.changePage}" onchange="submit()">
   <f:selectItems value="#{pageBean.selectPages}" />
</h:selectOneMenu>

The above codes for the changePage() method do not return the new selected page value from the h:selectOneMenu. Instead, it returns the page value prior to submit. I don't understand why.

Can someone please help? Have been stuck on this for 2 days now.

Answer

BalusC picture BalusC · Dec 7, 2009

Apparently you're doing a redirect instead of a forward, while the bean is request scoped. A redirect creates a new request, hereby garbaging all initial request scoped attributes, including request scoped beans. It will thus cause recreation of request scoped bean with all default properties. To solve this problem, remove the <redirect/> entry from the <navigation-case> entry in faces-config.xml, if any.

If this is for pure page-to-page navigation, I'd recommend another approach for this. Get rid of the valueChangeListener, have the page URL's as SelectItem values and replace submit() with:

onchange="window.location=this.options[this.selectedIndex].value"

You namely don't want to use POST for simple page-to-page navigation.

Hope this helps.

Edit: as per the comments, you actually want datatable pagination and this dropdown must instantly go to page X of the datatable at the same JSF page? In this case, forget my answer above, it wasn't clear from your question and I didn't realize that you want datatable pagination.

The as far posted information and code looks fine. Have you debugged the code to see what happens with property values? Isn't it nulled out afterwards? Is the correct value returned during render? Does the dropdown list return the expected items during render? That kind of trivial things. Maybe something else which you didn't post about is colliding with this all.

Edit 2: I actually created an SSCCE to see if it really works and as I expected, it just works. Your problem lies somewhere else. Maybe a buggy Converter? Maybe it was actually a redirect?

MyBean (request scoped):

public class MyBean {

    private Integer page;
    private List<SelectItem> pages = new ArrayList<SelectItem>();

    public MyBean() {
        for (int i = 1; i <= 10; i++) {
            pages.add(new SelectItem((i == 1) ? i : (i * 10)));
        }
    }

    public void changePage(ValueChangeEvent event) {
        if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
            setPage((Integer) event.getNewValue());
        } else {
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
        }
    }

    public Integer getPage() {
        return page;
    }

    public List<SelectItem> getPages() {
        return pages;
    }

    public void setPage(Integer page) {
        this.page = page;
    }

}

(by the way, you used String instead of Integer which is imho the wrong type for numerical values, but here it works fine with String as well)

JSF page:

<h:form>
    <h:selectOneMenu value="#{myBean.page}" onchange="submit()"
        valueChangeListener="#{myBean.changePage}">
        <f:selectItems value="#{myBean.pages}" />
    </h:selectOneMenu>
</h:form>

I used Mojarra 1.2_13 on Tomcat 6.0.20.

By the way, the valueChangeListener is entirely superfluous. It works as fine without it. JSF just sets the selected page during Update Model Values phase.