Skip to main content

h:dataTable w/contained input elements and state

2 replies [Last post]
markroy
Offline
Joined: 2010-02-09
Points: 0

Hi

I hope someone can help me. I'm trying to create a form somewhat like the one in allEvents.xhtml of the Virtual Trainer app in Ed Burns' JSF 2.0 book. My form is similar in that it uses an h:dataTable to display a set of rows that include an h:selectBooleanCheckbox. (In my case, the row also contains an h:inputText). So far, that's all working fine.

However, to complicate things, I've added an to change the contents of the datatable based on the menu selection. This is where things start to go wrong. When the menu selection changes, the dataTable does update to show the new set of rows. However, there seems to be some state in the dataTable or the view that does not get reset when the content changes.

This causes a couple of problems: When the initial menu selection is 'noSelectionOption' and the dataTable value is 'an empty list', then the menu selection changes, none of the input items' values are set when the form is submitted. It seems like dataTable remembered that the list is empty, and subsituting a longer list is confusing it. Or, is it the view that's confused because the number of input elements changed?

When I initialize the menu selection to one that has a non-empty dataTable list associated with it, things work as desired, but changing menu selections again confuse things (checkboxes remain checked, rows beyond those in the initial list don't get their values set.) Hopefully, you're still with me.

It seems like this should be do-able. What am I missing? I've boiled it down to a simple example. Your help is greatly appreciated. Here's the code.

selectitems.xhtml

<br />
<?xml version="1.0" encoding="ISO-8859-1" ?></p>
<p>      Category </p>
<p>      Options </p>
<p>

OptionsBean.java

<br />
package org.example;</p>
<p>import java.util.ArrayList;<br />
import java.util.List;</p>
<p>import javax.faces.application.FacesMessage;<br />
import javax.faces.bean.ManagedBean;<br />
import javax.faces.component.UIData;<br />
import javax.faces.context.FacesContext;<br />
import javax.faces.model.DataModel;<br />
import javax.faces.model.ListDataModel;<br />
import javax.faces.model.SelectItem;</p>
<p>@ManagedBean<br />
public class OptionsBean<br />
  {<br />
  int category = getCategoryNotSelected();<br />
  private UIData optionTable;<br />
  private DataModel optionData = new ListDataModel();<br />
  private List optionList = new ArrayList();</p>
<p>  // static data for demonstration use<br />
  private static List categories = new ArrayList();<br />
  private static List sizeOptionList = new ArrayList();<br />
  private static List colorOptionList = new ArrayList();<br />
  private static List styleOptionList = new ArrayList();</p>
<p>  static<br />
    {<br />
    OptionsBean o = new OptionsBean();<br />
    sizeOptionList.add( o.new OptionTableRow( "small" ) );<br />
    sizeOptionList.add( o.new OptionTableRow( "medium" ) );<br />
    sizeOptionList.add( o.new OptionTableRow( "large" ) );<br />
    sizeOptionList.add( o.new OptionTableRow( "other", "specify" ) );</p>
<p>    colorOptionList.add( o.new OptionTableRow( "red" ) );<br />
    colorOptionList.add( o.new OptionTableRow( "green" ) );<br />
    colorOptionList.add( o.new OptionTableRow( "blue" ) );<br />
    colorOptionList.add( o.new OptionTableRow( "other", "specify" ) );</p>
<p>    styleOptionList.add( o.new OptionTableRow( "modern" ) );<br />
    styleOptionList.add( o.new OptionTableRow( "traditional" ) );</p>
<p>    categories.add( new SelectItem( 1, "size" ) );<br />
    categories.add( new SelectItem( 2, "color" ) );<br />
    categories.add( new SelectItem( 3, "style" ) );<br />
    }</p>
<p>  public OptionsBean()<br />
    {<br />
//    setCategory( getCategoryNotSelected() );<br />
    setCategory( 3 );<br />
    }</p>
<p>  public int getCategoryNotSelected()<br />
    {<br />
    return -1;<br />
    }</p>
<p>  public boolean isOptionSelected()<br />
    {<br />
    OptionTableRow row = (OptionTableRow) optionTable.getRowData();<br />
    return row.selected;<br />
    }</p>
<p>  public void setOptionSelected( boolean selected )<br />
    {<br />
    OptionTableRow row = (OptionTableRow) optionTable.getRowData();<br />
    row.selected = selected;<br />
    }</p>
<p>  public String getOptionDetail()<br />
    {<br />
    OptionTableRow row = (OptionTableRow) optionTable.getRowData();<br />
    return row.detail;<br />
    }</p>
<p>  public void setOptionDetail( String detail )<br />
    {<br />
    OptionTableRow row = (OptionTableRow) optionTable.getRowData();<br />
    row.detail = detail;<br />
    }</p>
<p>  public String submit()<br />
    {</p>
<p>    int count = 0;<br />
    for ( OptionTableRow opt : optionList )<br />
      if ( opt.selected )<br />
        count++;</p>
<p>    if ( count == 0 )<br />
      {<br />
      FacesContext fc = FacesContext.getCurrentInstance();<br />
      fc.addMessage( null, new FacesMessage( FacesMessage.SEVERITY_ERROR, "At least one option must be selected", null ) );<br />
      return null;<br />
      }</p>
<p>    return "showoptions";<br />
    }</p>
<p>  public UIData getOptionTable()<br />
    {<br />
    return optionTable;<br />
    }</p>
<p>  public void setOptionTable( UIData optionTable )<br />
    {<br />
    this.optionTable = optionTable;<br />
    }</p>
<p>  //  public List getOptionList()<br />
  //    {<br />
  //    return optionList;<br />
  //    }<br />
  //<br />
  //  public void setOptionList( List optionList )<br />
  //    {<br />
  //    this.optionList = optionList;<br />
  //    }</p>
<p>  public DataModel getOptionData()<br />
    {<br />
    optionData = new ListDataModel( optionList );<br />
    optionData.setRowIndex( -1 );</p>
<p>    return optionData;<br />
    }</p>
<p>  public void setOptionData( DataModel optionData )<br />
    {<br />
    this.optionData = optionData;<br />
    }</p>
<p>  public List getCategories()<br />
    {<br />
    return categories;<br />
    }</p>
<p>  public void setCategories( List categories )<br />
    {<br />
    OptionsBean.categories = categories;<br />
    }</p>
<p>  public int getCategory()<br />
    {<br />
    return category;<br />
    }</p>
<p>  public void setCategory( int category )<br />
    {<br />
    this.category = category;<br />
    switch ( category )<br />
      {<br />
      case 1:<br />
        optionList = sizeOptionList;<br />
        break;<br />
      case 2:<br />
        optionList = colorOptionList;<br />
        break;<br />
      case 3:<br />
        optionList = styleOptionList;<br />
        break;<br />
      }</p>
<p>    }</p>
<p>  public class OptionTableRow<br />
    {<br />
    private String label;<br />
    private boolean selected = false;<br />
    private String detailLabel = null;<br />
    private String detail = null;</p>
<p>    public OptionTableRow()<br />
      {<br />
      }</p>
<p>    public OptionTableRow( String label )<br />
      {<br />
      this.label = label;<br />
      }</p>
<p>    public OptionTableRow( String label, String detailLabel )<br />
      {<br />
      this.label = label;<br />
      this.detailLabel = detailLabel;<br />
      }</p>
<p>    public boolean isSelected()<br />
      {<br />
      return selected;<br />
      }</p>
<p>    public void setSelected( boolean selected )<br />
      {<br />
      this.selected = selected;<br />
      }</p>
<p>    public String getDetail()<br />
      {<br />
      return detail;<br />
      }</p>
<p>    public void setDetail( String detail )<br />
      {<br />
      this.detail = detail;<br />
      }</p>
<p>    public String getLabel()<br />
      {<br />
      return label;<br />
      }</p>
<p>    public void setLabel( String label )<br />
      {<br />
      this.label = label;<br />
      }</p>
<p>    public String getDetailLabel()<br />
      {<br />
      return detailLabel;<br />
      }</p>
<p>    public void setDetailLabel( String detailLabel )<br />
      {<br />
      this.detailLabel = detailLabel;<br />
      }</p>
<p>    public String toString()<br />
      {<br />
      StringBuffer sb = new StringBuffer();<br />
      sb.append( label );<br />
      if ( !selected )<br />
        sb.append( " [not selected]" );<br />
      else<br />
        if ( detailLabel != null )<br />
          sb.append( " " + detailLabel + "=" + detail );<br />
      return sb.toString();<br />
      }</p>
<p>    }</p>
<p>  }<br />

showoptions.xhtml

<br />
<?xml version="1.0" encoding="ISO-8859-1" ?></p>
<p>      Options </p>
<p>          #{data.selected}</p>
<p>

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
rbsrodrigues
Offline
Joined: 2010-07-28
Points: 0

Hi,

I will make some suggestions. I don't know if will work, but you can try :)

1) Istead of use "" why do you don't use:? The "f:ajax" component is one of the best features of JSF 2.

2) You can use the "@ViewScoped" annotation in your bean too. This will save the state of your bean between the requests of your screen to the server.

@ManagedBean
@ViewScoped
public class OptionsBean { ...
}

Cheers

rbsrodrigues
Offline
Joined: 2010-07-28
Points: 0

Hi,

I will make some suggestions. I don't know if will work, but you can try :)

1) Istead of use "" why do you don't use:? The "f:ajax" component is one of the best features of JSF 2.

2) You can use the "@ViewScoped" annotation in your bean too. This will save the state of your bean between the requests of your screen to the server.

@ManagedBean
@ViewScoped
public class OptionsBean { ...
}

Cheers