JSF master / detail question

[nobr]In my app I have a:

- a selectone listbox

- a details select many listbox, the contents of which are dependent upon the selected item in the select one listbox

- a command button which acts process the items from the selectmany listbox

the backing bean is in request scope. The actual JSP and backing bean are attached below:

my problem:

- when I click the command button I get validation errors caused by the selectmany listbox during the validation phase. This is because:

-- the backing bean is in request scope and a new instance is created, but the appropriate items have not been filled yet, because the update model values phase has not been reached yet.

I feel like I'm on the wrong track altogether. Can someone point me in the right direction about how I should approach this problem? Thanks.

-- JSP

<f:view>

<f:loadBundle basename="messages" var="msgs"/>

<html>

<head>

</head>

<body>

<h:form>

<h:outputText value="#{msgs.master}"/>

<br>

<h:message for="masterListbox"/>

<h:selectOneListbox onchange="submit()" immediate="true" value="#{bb.selectedMasterId}">

<f:selectItems value="#{bb.masterRecords}"/>

</h:selectOneListbox>

<br>

<h:outputText value="#{msgs.details}"/>

<h:message for="detailsListbox"/>

<h:selectManyListbox value="#{bb.selectedDetailIds}">

<f:selectItems value="#{bb.detailRecords}"/>

</h:selectManyListbox>

<br>

<h:commandButton value="#{msgs.processDetails}" actionListener="#{bb.processDetails}"/>

</h:form>

</body>

</html>

</f:view>

-- Backing Bean

publicclass BackingBean{

private IDao dao;

private List<SelectItem> masterRecords;

private List<SelectItem> detailRecords;

private Integer selectedMasterRecordId;

private Integer[] selectedDetailRecordIds =new Integer[0];

public List<SelectItem> getMasterRecords(){

return this.masterRecords;

}

public List<SelectItem> getDetailRecords(){

return this.detailRecords;

}

// the dao is injected through the managed bean facilities

publicvoid setDao(IDao dao){

this.dao = dao;

this.masterRecords = dao.getMasterRecords();

// by default the first record will be preselected

this.selectedMasterRecordId = (Integer)this.masterRecords.get(0).getValue();

this.detailRecords = dao.getDetailRecords(this.selectedMasterRecordId);

}

public Integer[] getSelectedDetailIds(){

return this.selectedDetailRecordIds;

}

publicvoid setSelectedDetailIds(Integer[] selectedDetailRecordIds){

this.selectedDetailRecordIds = selectedDetailRecordIds;

}

public Integer getSelectedMasterId(){

return this.selectedMasterRecordId;

}

publicvoid setSelectedMasterId(Integer newMasterId){

this.selectedMasterRecordId = newMasterId;

// this is a good time to set the details.

this.detailRecords = dao.getDetailRecords(this.selectedMasterRecordId);

}

publicvoid processDetails(ActionEvent actionEvent){

// do some processing. But this is never reached due to validation errors on the details

// selectManyListbox

}

}

[/nobr]

[5291 byte] By [bob_robertsona] at [2007-11-26 16:05:36]
# 1
>>> <h:selectManyListbox value="#{bb.selectedDetailIds}">wat abt this "#{bb.selectedDetailIds" value in your backing bean?are u getting this as selectitems ?
Christophersama at 2007-7-8 22:27:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2
No, the SelectItems are pretty simple. The values are Integers and the labels are Strings.
bob_robertsona at 2007-7-8 22:27:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3
Keep it s backing bean property as List <selectitems> and try it out.
Christophersama at 2007-7-8 22:27:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4

When you inject the DAO, you are preselecting the the selected master record ID to be the first entry in your master listbox.

That's dumb.

It means if you select some details in the selectmany listbox and submit your form JSF will attempt to validate the selected IDs against the details SelectItems, which belong to the default preselected master record ID, as we've not set the model values yet.

If you modify your code like this it should work:

First, add some ids to your form elements

<h:form id="myForm">

<h:selectOneListbox id="masterRecordsListbox" onchange="submit()" immediate="true" value="#{bb.selectedMasterId}">

then

public void setDao(IDao dao) {

this.dao = dao;

this.masterRecords = dao.getMasterRecords();

Map parameters = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

String masterRecordParam = (String)parameters.get("myForm:masterRecordsListbox");

if (masterRecordParam != null) this.selectedMasterRecordId = Integer.parseInt(selectedRoleId);

else this.selectedMasterRecordId = (Integer)this.masterRecords.get(0).getValue();

this.detailRecords = dao.getDetailRecords(this.selectedMasterRecordId);

}

Now you'r backing bean is using the correct master record id and life should be better.

bob_robertsona at 2007-7-8 22:27:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5
thanks, you're really smart.
bob_robertsona at 2007-7-8 22:27:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...