webtier@glassfish.java.net

Re: Using h:commandButton with h:dataTable using JSF (mojarra-1.2_12) & Tom

From: <webtier_at_javadesktop.org>
Date: Sat, 28 Mar 2009 22:41:42 PDT

I have a similar issue. Here's some sample code.

Search.java:
[code]
public class Search {
        private List<String> results;
        
        public Search() {
                results = new ArrayList<String>();
                results.add("1");
                results.add("2");
        }
        
        public void search(ActionEvent ae) {
                results = new ArrayList<String>();
                results.add("1");
                results.add("2");
                results.add("3");
                results.add("4");
        }
        
        public void onResultClick(ActionEvent ae) {
                System.out.println("clicked!!!");
        }

        public List<String> getResults() {
                return results;
        }

        public void setResults(List<String> results) {
                this.results = results;
        }
}
[/code]

search.jsp:
[code]
<f:view>
<tr:document>
<tr:form>
        <tr:commandButton actionListener="#{search.search}" text="perform search"/>
        <tr:table value="#{search.results}" var="result">
                <tr:column>
                        <tr:outputText value="#{result}"/>
                </tr:column>
                <tr:column>
                        <tr:commandButton actionListener="#{search.onResultClick}" text="click me"/>
                </tr:column>
        </tr:table>
</tr:form>
</tr:document>
</f:view>
[/code]

Okay now if I give search a scope of "session" it works as expected. When you first load the page, there are 2 results shown. If you click either button in the table it says "clicked!!!" in the eclipse console window. If you click "perform search" then you get 4 results, and all of those buttons work as well.

If you change the scope to "request" then it gets odd. You load the page and get 2 results. Clicking either button works. Then you click "perform search" and get 4 results. If you click any of the buttons, it goes back to showing 2 results. This is expected because I know that when the page renders, it only has the 2 results generated by the constructor since the search() method wasn't called. However, the unexpected part is that buttons 3 and 4 don't print out the "clicked!!!" message.

I've been researching this problem all day and I think I know what's going on. When JSF processes the postback, the first thing it does is actually re-execute the jsp page to create all of the components on the page, such as the table, buttons, and backing bean. Once that info is in memory, it then looks at what the user did, such as click a button, and calls the appropriate actionlistener.

However, since the constructor doesn't create the full results list, the table it creates in memory doesn't have all of the rows, and thus not all of the buttons either. When it gets to the next stage and tries to execute the actionlistener for button 4, it can't find button 4 so it ignores the event!

On the other hand, when you're using session scope, JSF doesn't instantiate the search bean on every request. Instead it reuses the same actual object, so the results list still has all 4 elements in it when the postback is executed, it creates the table with 4 rows and 4 buttons, and then it successfully finds button 4 and executes its actionlistener.

I don't want to use the session scope for search results because I'd like to let users open multiple windows and perform independent searches. I also don't want to re-execute the search in the constructor just to recreate the data so that my events fire correctly, because that would slow it down unnecessarily. Not to mention from a consistency standpoint the search results could have changed since the original search, so it would occasionally perform the wrong action!

One solution I'm going to try is to create dummy records in the constructor rather than execute the actual search. That way the event should still fire. I'm not sure I'll be able to access the data I need in the click handler though.

Another possible solution is to use the pageFlowScope scope type provided by the Apache Trinidad project (which I'm already using). It's a mix between request and session so it might work.
[Message sent by forum member 'stdarg' (stdarg)]

http://forums.java.net/jive/thread.jspa?messageID=339467