1

I'll be very pleased to get a decent explaination for the following case.

Here's a simple JSF with two forms and text output:

<h:body>
<h:form>
<h:commandButton value="Go" action="#{wierdBean.doWierdStuff}"/>
</h:form>

<h:form>
<h:dataTable value="#{wierdBean.pages}" var="page">
<h:column>
<h:commandButton value="the same go action?" action="#{wierdBean.doWierdStuff}"/>
</h:column>
</h:dataTable>
</h:form>
</h:body>

<h:dataTable value="#{wierdBean.pages}" var="page">
<h:column>
<h:outputText value="#{page}"/>
</h:column>
</h:dataTable>

'Go' button at the top is supposed to do the same thing as the 'the same go action?' buttons.

Backing WierdBean is:

public class WierdBean implements Serializable {

private int buttonsCount;

public WierdBean() {
System.out.println("WierdBean()");
}

@PostConstruct
public void postConstruct() {
System.out.println("postConstruct()");
}

public Integer[] getPages() {
System.out.print("getPages() buttonsCount(): " + buttonsCount);
Integer[] pages = new Integer[buttonsCount];
for (int i = 0; i < pages.length; i++) {
pages[i] = new Integer(i);
}
return pages;
}

public String doWierdStuff() {
System.out.println("doWierdStuff()");
buttonsCount = 2;
return "wierd";
}
}

When I enter the page I get:

INFO: WierdBean()
INFO: postConstruct()
INFO: getPages() buttonsCount(): 0 (16 times)

and I seen only the 'Go' button. That's understandable.

After Pressing the 'Go' button I get:

INFO: WierdBean() 
INFO: postConstruct() 
INFO: getPages() buttonsCount(): 0 (19 times) 
INFO: doWierdStuff() 
INFO: getPages() buttonsCount(): 2 (16 times)

Nice, doWierdStuff is called and then I get 2 'the same go action' buttons and 2 text outputs. That's fine.

However, when I press any of the the 'the same action' buttons, which are supposed to do the same thing as 'Go' button - call the doWierdStuff method - I get:

INFO: WierdBean() 
INFO: postConstruct() 
INFO: getPages() buttonsCount(): 0 (44 times)

There is only 'Go' button visible.

Why is that?

Dzik
  • 399
  • 1
  • 5
  • 17
  • I think I found the answer myself. I put the code from getPages method inside the doWierdStuff making getPages a legal getter. In this case I get only 'GO' button no matter what I do. Just another reason for making your getters GETTERS ONLY! – Dzik Dec 21 '11 at 15:15

1 Answers1

0

Your concrete problem is two-fold: the bean is clearly request scoped instead of view scoped and you're doing business job inside a getter method instead of the (post)constructor or an (action)listener method.

A request scoped bean get recreated on every individual request and is not reused on subsequent requests on the same view. All properties like buttonsCount are reinitialized to their defaults. When clicking a command link/button in a datatable, you need to make sure that exactly the same datamodel is been preserved as in initial request. If you don't do that, JSF won't be able to find the action to be invoked. The bean needs to live as long as you're interacting with the same view by returning null or void. This can be achieved by putting the bean in the view scope by @ViewScoped (or when you're still on obsolete JSF 1.x, by Tomahawk's <t:saveState> component).

A backing bean getter method should only return data which is already prepared beforehand, not to prepare the data itself. The getter method is supposed to solely be an access point to the data. This is because the getter method can be called multiple times during a request-response cycle, especially if referenced in an UIData component and/or the rendered attribute.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks. That was a great answer! :) Excpecially the part about the datamodel. That explains why the buttons were sort of 'retarded'. – Dzik Dec 21 '11 at 15:25