Monday, December 18, 2017

Problems with Primefaces Picklists

Primefaces is awesome. JSF is awesome.

Know what isn't awesome? The documentation.

Don't get me wrong... The Primefaces document and the Showcase demo site are very good for introducing the components and the basics on how to use them. The problem is that sometimes they're a little too basic. For example, the picklist component. It says right in the Primefaces PDF that most often, pojos will be used with the picklist, and that it is necessary to implement a Converter to handle it... and that's it. It goes on to show how some facets can be used to make the component look more spiffy, but the developer is left with very little information on what the Converter is for, exactly and how to implement it.

That's why this post exists.

So here's an example that will hopefully help.

<p:picklist converter="#{shipConverter}" itemlabel="#{ship.name}" value="#{backingBean.pickDLM}" var="ship"/>

So here, the converter is just the name we give to our instance of the ShipConverter class, which implements Converter.  itemLabel is the field within one of the contained objects that will be displayed in the picklist windows.  Value is the DualListModel which is defined in the backing bean and serves as the source of data for the picklist.  Var is the reference to each individual item, the same as in a table or tree.

So how does that DualListModel work?

In your backing bean, you'll need your data source for the picklist. 

DualListModel<Ship> pickDLM = null;  //matches the value field on the view
List<Ship> shipSource = DatabaseSourceObject.getShips();
List<Ship> shipTarget = newArrayList<Ship>();

Notice that the source object is a list of Ship objects which will populate the left pane of the picklist.  The target is the right pane, and is initially empty.  If your project needed to pre-populate a few items in the right pane, you would add them to the target object here.  So now we put it all together:

pickDLM = new DualListModel<Ship(shipSource, shipTarget);

So then all you need in your backing bean is the getters and setters for the DualListModel. 

Now for the Converter...

@FacesConverter(value="shipConverter")
@Managedbean(name="shipConverter")
public class ShipConverter implements Converter{

  public ShipConverter(){}//Constructor Stub
  
  //This method provides an implementation for converting the strings in the pickList view back into the objects they represent.
  @Override
  public Object getAsObject(FacesContext context, UIComponent uiComponent, String value){
  pickList pickList = (PickList)uiComponent;
  DualListModel listModel = (DualListModel)pickList.getValue();
  for(Object item : listModel.getSource()){
    Ship ship = (Ship)item;
    if(ship.getName().equals(value)){
      return ship;
    }
  }
}

  //This method provides an implementation for getting the String value of an object in the picklist.
@Override
public String getAsString(FacesContext context, UIComponent uiComponent, Object object){
  String result = ((Ship)object).getName();
  return result;
}
}

That's it.  The idea is to specify exactly how to switch back and forth between the collection objects and their String representations in the picklist.

Enjoy!


No comments:

Post a Comment