Think I've cracked it - can't believe there're only two of us that have seen this.
The problem appears to be that my data table doesn't have a fixed number of rows and until some action has been performed will contain zero rows. My page has a search form, and the table shows the results of a search. On initial navigation to the page the search results are empty. My table is bound to "customers" value - here's the getter foe my table's rows: public DataModel getCustomers() { logger.debug("get customers called: customers = " + customers); Exception e = new Exception("Fake exception"); logger.debug("", e); ListDataModel model = new ListDataModel(); if (customers == null) { customers = new ArrayList<Customer>(0); } model.setWrappedData(customers); return model; } The search button on the page is bound to the search action in my bean... public void search() { logger.debug("search called"); String v_email = (getEmail() != null) ? getEmail() : "" ; String v_screenName = (getScreenName() != null) ? getScreenName() : "" ; String v_firstName = (getFirstName() != null) ? getFirstName() : "" ; String v_lastName = (getLastName() != null) ? getLastName() : "" ; customers = customerManagement.listCustomers( v_email, v_screenName, v_firstName, v_lastName); if ( customers == null || customers.size() == 0 ) { String message = (String) getMessages().getMap().get(NO_RESULTS); getFacesContext().addMessage(null, new FacesMessage(message)); } } So until the search button is pressed my table data is empty. Ok. So the secret of the failure lies in when the getter is called and by what. The lifecycle of the page is: 1. ==== initial navigation ===== Bean created, getCustomers() called during render response phase when table is rendered. Returns an empty list. 2. ==== search performed: users fills in a field value and hits search. ===== getCustomers() called twice. First call: apply request values phase. Called because UIData fires UIData.setRowIndex(). Returns empty list. Second call: render response phase. Called when table is rendered. Search() has been called now (during invoke app phase) so getCustomers() returns a list with (for example) two rows. 3. ==== user details accessed: user clicks the actionlink in the first row of the table ============ getCustomers() called twice. First call: apply request values phase. Called because UIData does a UIData.setRowIndex(). Customers is null as no search has been performed. Second call: render response phase. Called when table is rendered. No search() performed so getCustomers() returns a empty list. The key is in the first call to getCustomers() during the third navigation. The stack trace when that call is made is... java.lang.Exception: Fake exception at myclass.UserSearchViewController.getCustomers(UserSearchViewController.j ava:103) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.jav a:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessor Impl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.myfaces.el.PropertyResolverImpl.getProperty(PropertyResolverI mpl.java:400) at org.apache.myfaces.el.PropertyResolverImpl.getValue(PropertyResolverImpl .java:71) at org.apache.shale.faces.ShalePropertyResolver.getValue(ShalePropertyResol ver.java:137) at org.apache.myfaces.el.ELParserHelper$MyPropertySuffix.evaluate(ELParserH elper.java:532) at org.apache.commons.el.ComplexValue.evaluate(ComplexValue.java:145) at org.apache.myfaces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:37 8) at javax.faces.component.UIData.getValue(UIData.java:779) at javax.faces.component.UIData.createDataModel(UIData.java:545) at javax.faces.component.UIData.getDataModel(UIData.java:534) at javax.faces.component.UIData.setRowIndex(UIData.java:147) at javax.faces.component.UIData.processColumnChildren(UIData.java:477) at javax.faces.component.UIData.processDecodes(UIData.java:381) ... One of the things that happens in processDecodes() is that any ActionEvents are queued for later invocation. We have fired an action event on the table by clicking on a row's commandLink. However, because the call to getCustomers() returns an empty list, the UIData component believes that the table had no rows. It therefore stops processing the table at that point so the commandLink action event is never queued!!!!!! As far as JSF is now concerned, no event happened. It therefore defaults to re-rendering the same page. The problem now is how do I fix it? Well I've fixed it by making my bean session scoped so that the value of customers is preserved across requests. Then the first call to getCustomers() returns it's value at the previous page rendering. Maybe someone can tell me if there's some cleverer fix than that - maybe using phase listeners or something? Is it a bug? I think so. It seems to me that UIData relying on the request-scoped backing bean to tell it how many rows the table has is incorrect; there is an assumption there that the call to getValue() will always return the same result. Sounds like a bug to me. What do the community think? BTW, Thanks Ryan for your response. Knowing I wasn't the only one seeing this behaviour motivated me to take a deeper look!! I guess your stuff fails because when you move your data connection to prerender() the first call to your getter is returning an empty list. Cheers, Ian. -----Original Message----- From: Ryan [mailto:[EMAIL PROTECTED] Sent: 05 May 2006 06:48 To: Struts Users Mailing List Cc: Ian.Priest Subject: Re: [shale][clay] commandLink in dataTable not working I'm experiencing the same behavior, and I've built all my views in Clay as well. Here's an interesting behavior that I see in my Controller (extending the Shale Controller). I have Page A that displays a data table with image links throughout that link to an action, let's call it "edit". This is backed by a managed PageAViewController. If I put the following calls in init(): - a call to the spring-jsf resolver to get my service object - make the service object call (underlying is a Hibernate call) then, Page A displays the data table, and the link action method is called and I'm brought to Page B. Now, if I move the service object Hibernate call to prerender() in PageAViewController (where I think it should be), the data table is still displayed, but this time, when I click on any of the links, the link action method is never called, and the page is redisplayed. I can't figure out what I'm doing wrong for the life of me, seems like everything should work. I've even added the immediate="true" as Gary suggested, but that doesn't help to any avail. I find it interesting that if all the calls are init(), I get the right page, but I don't want to make the Hibernate data call all the time. Anyone else seen this? Anybody have any debugging tips? _RK On 5/4/2006, "(Gary VanMatre)" <[EMAIL PROTECTED]> wrote: > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]