Radio and Checkbox in primefaces datatable - java

I have to put radio and chechbox controls in primefaces's 2.2.1 datatable but not as a selection mode controls. I want to bind that controls as a values for the backing bean.
For example:
A have a list of some configurations and in that list only one configuration can be active at one time (radiobox) but every single configuration can be active or not (selectbox).
Datatable doesn't have to be editable, because I will change values in another window. Only controls should be in the datatable.
Is that possible?

Yes, it is definitely possible I do this all the time in my datatables. However, you need to keep in mind that each row will require identification. You can do this with objects or parameters to your listener:
//Backing Bean
#ViewScoped
public class TestBean
{
private ArrayList<Element> elements;
TestBean(){...}
public ArrayList<Element> getElements(){...} //Initialize things here
public class Element
{
/* getter/setter and initialization assumed */
private boolean selected;
private String radioSelection = "one";
private String[] radioChoices = new String[]{"one", "two", "three"};
public void selectMe(ActionEvent evt)
{
System.out.println("Selected -> " + this);
}
}
}
//HTML
<p:dataTable value="testBean.elements" var="element">
<p:column>
<p:commandButton value="Select" actionListener="#{element.selectMe}"
</p:column>
<p:column>
<h:selectBooleanCheckbox value="#{element.selected}" />
</p:column>
<p:column>
<h:selectOneRadio value="#{element.radioSelection}">
<f:selectItems
value="#{element.radioChoices}"
var="item"
itemLabel="#{item}"
itemValue="#{item}"
/>
</h:selectOneRadio>
</p:column>
</p:dataTable>
You can (and might want to) use a parameter using the ID from the element or whatever your preferred pattern is. The key is remembering that each row has its own id and you're creating a set of elements, not a single element. That's where you're most likely to get bound up. Seeing as how each button is a first class citizen you should be able to whatever you want with it.
Edit:
I added a Radio/Checkbox example. It sounds like you're new to JSF so I'd advise reading up on the SelectItem class and run through how combo-boxes etc... work. The key to remember (as I stress above) is that you're rendering a lot of components so if you share a value it can easily lead to behavior you don't want. Encapsulate everything and you're usually in good shape.) You can also look at bindings as a possible solution. It all depends on where you'd rather write your code.

Related

Primefaces DataTable display only the last item

the Datatable is displaying only the last item added, it seems that every time i press the commandButton the method rewrites the list, what can I do to avoid that?
JSF
<p:commandButton action="#{productoBean.setPedidoActual()}" value="Agregar" update="dt"/>
</p:panelGrid>
<p:dataTable value="#{productoBean.pedidoActual}" var="pedi">
<p:column headerText="Nombre">
<h:outputText value="#{pedi.descripcion}"/>
</p:column>
</p:dataTable>
Bean
public void setPedidoActual() {
Producto pro = productoFacade.find(idProducto);
listPedidoActual.add(pro);
}
public List<Producto> getPedidoActual() {
return listPedidoActual;
}
Your setPedidoActual() method seems like to receive only one item based on the facade service find(idProducto), is that correct? Have you checked what the remote service returns? Probably there is in fact just one record.
Beside that, try to rename your setter/getter from
getPedidoActual() / setPedidoActual()
into
getListPedidoActual() setListPedidoActual()
Now your method names are consistent with your attribute.
EDIT: What happened to the panelGrid tag? Have you purposely omitted or where does it start?

JSF: rich datatable filtering, dynamic columns, and passing arguments

I'm working on a rich:datatable on a JSF page. The table can get pretty big and is paged with a rich:datascroller. Most of the columns are hardwired and will always be there, but then there are some optional columns based on additional values that need to be generated for each potential additional value. I've been able to make this happen easily enough. However, I'm running into a problem with filtering.
I'm using a filter on each column. It's placed in the header with the column label and sorting function. That much is working fine on each column, but I'm hitting a snag on filtering due to the way filtermethod works by default. Here's a quick example:
<rich:datatable id="thetable" value=#{backingBean.stuff} var="b">
<!-- First column, standard filter method, works just fine -->
<rich:column sortBy="#{b.field1}" filterMethod="#{filterBean.filterField1}">
<f:facet name="header">
<ui:fragment>
<h:outputText value="Field 1" />
<h:inputText value="#{filterBean.filterMap['Field1']}" />
</ui:fragment>
</f:facet>
#{b.field1}
</rich:column>
<c:forEach items="#{backingBean.extraStuff}" var="e">
<rich:column sortBy="#{b.getExtra(e)}" filterMethod="???">
<f:facet name="header">
<ui:fragment>
<h:outputText value="#{b.getExtra(e).description}" />
<h:inputText value="#{filterBean.filterMap['b.getExtra(e).code']}" />
</ui:fragment>
</f:facet>
#{b.getExtra(e).description}
</rich:column>
</rich:datatable>
The ??? will be covered shortly. As for the filter bean:
public class FilterBean {
public Map<String, String> filterMap = new HashMap<String, String>();
public boolean filterField1(Object current){
return ((BackingBean) current).contains(filterMap.get("Field1"));
}
}
It's fairly straightforward. The filter inputText binds to a preset string in the hashMap, which is retrieved in the method and used to filter so I don't need a separate field for every filter. This is working great, but I still need a separate method for each filter, which brings me to the ??? in the JSF code...
What I'd like to do is pass arguments to the filter method to account for the dynamic columns. In fact, I'd like to simplify the whole class with a single filter method and pass the mapped String in along with the field from the current object. However, this isn't working. I've tried:
filterMethod="#{filterBean.filterStuff(b, 'Field1')}"
but I wind up getting the filter string just fine, but null for the current object. I'm not sure what's going on. If I'm reading the dependencies in the project correctly, I'm using some pretty old versions of EL, JSF, JSP, etc, and I really have no way of changing that. The project does use Seam, though, and I've passed arguments successfully in EL before in this project. Is it just that EL 2.2 supports passing objects while older versions only supported primitives and Strings? Is there any way for me to make this happen or am I stuck without building a ton of extra stuff from the ground up?
Okay, looks like this might be possible with Seam, but it doesn't like iteration variables. I CAN pass the object if I refer to an index in the List from the backing bean, but that doesn't help as I have no way of telling it to search every row...
My use case is a bit different, but basically I had the same problem and found a working solution.
The use case: I have several XHTML-files with their backing-beans all offering a table with a list of entities of different types. In this table there are several columns for some attributes of the entities with the possibility to filter. Since the built-in filter does only a "starts-with" search and I need a more advanced one, I have to use the filterMethod.
But I did not want to mess up my backing-beans with hundreds of simple filter-methods doing all exactly the same (only with different attributes). So I was looking for a more generic way - and this is my approach:
In the backend, I created a new class named FilterMethodWrapper (for easier understanding I put it as nested static class here) and a method to access it:
import org.apache.commons.beanutils.PropertyUtils;
public class BackendBean
{
private String[] filterValues;
// initialize filterValues somewhere, add getter and setter
public static class FilterMethodWrapper
{
private final String fieldName;
private final String filterValue;
public FilterMethodWrapper(final String fieldName, String filterValue)
{
this.fieldName = fieldName;
this.filterValue = filterValue;
}
public boolean doFilter(Object current) throws ...
{
final String stringValue = (String) PropertyUtils.getSimpleProperty(current, fieldName);
// compare stringValue and filterValue somehow (e.g. contains)
// and return result
}
}
public FilterMethodWrapper getFilterMethodWrapper(String fieldName, int filterValueIndex)
{
return new FilterMethodWrapper(fieldName, getFilterValues()[filterValueIndex]);
}
}
And in the XHTMLs use it as follows:
<rich:column filterMethod="#{backendBean.getFilterMethodWrapper('username', 0).doFilter}" filterEvent="onkeyup" >
<f:facet name="header">
<h:panelGrid style="display:inline;">
<h:outputText value="Username"/>
<h:inputText value="#{backendBean.filterValues[0]}" />
</h:panelGrid>
</f:facet>
<h:outputText value="#{_item.username}" />
</rich:column>
Edit: I'm using JSF 1.2 and RichFaces 3.3.3.Final
Edit2: instead of writing the FilterMethodWrapper you could also use some Predicate-implementation and use the apply-method in the frontend (or you write your own Predicate-implementation according to this proposal which is more reusable than this FilterMethodWrapper)

open new page (navigate to new site) when selecting a dataTable row

There a several related question on this topic on SO and elsewhere, but I couldn't find a definitive answer on this specific question.
I have a p:dataTable and I want the possibility to click on a row and open a detail page (a new page, not a dialogue or window).
I have solved it this way (which I have from the primefaces website, for some reason it is no longer there: http://web.archive.org/web/20101001223235/http://www.primefaces.org/showcase/ui/datatableRowSelectionInstant.jsf):
<p:dataTable var="order" value="#{orderBean.orders}" selection="#{orderBean.selectedOrder}" selectionMode="single" rowKey="#{order.number}">
<p:ajax event="rowSelect" listener="#{orderBean.orderSelect}"/>
<p:column ... />
</p:dataTable>
The navigation is then executed in the bean:
public void orderSelect(SelectEvent event) {
ConfigurableNavigationHandler nh = (ConfigurableNavigationHandler)FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nh.performNavigation("orderDetail?faces-redirect=true");
}
My Question: is there a way of doing this just inside JSF without the help of a backing bean?
I am also asking because they removed the code exmaple from the primefaces site, which might be an indication that this is not the right way of doing something like that.
Wrap the cell(s) of interest in a simple <h:link>.
<p:column>
<h:link outcome="orderDetail">
...
</h:link>
</p:column>
Use if necessary CSS display:block on the link to let it span the entire cell. You can if necessary pass request parameters using a nested <f:param>.
since it is an ajax request, typically the request/response is used to re-render some components in the web page. What you could do is
<p:ajax event="someventofintrest" onsuccess="javascript:myjsmethod();"></p:ajax>
and
<p:remotecommand name="myjsmethod" action="#{mybean.mybeanmethod}" />
and in the backing bean
public String mybeanmethod(){
return "mynewpage"; // Navigate away to mynewpage.xhtml
}
HTH.
As I didn't find a really perfect solution, this is how I do it now.
I have now a "navigator" class like this
#Component
public class Navigator {
public void nav(String page) {
UIHelper.navigateTo(page);
}
}
And I call this class from my ajax event:
<p:ajax event="rowSelect" listener="#{navigator.nav('orderDetail')}"/>
As I said, not really perfect, but I like the fact that I don't have to write code in my backing bean. (Of course I have to write code for the Navigator, but that I can re-use.)

How to sort a Column in a dataTable. JSF 2.0

I'm building a WebApp in jsf 2.0 and it's about storing information and displaying it on the screen. so I've put in some "http://java.sun.com/jsf/html" dataTables to disply some lists. My Java code returns a List and then displays them on screen. but now I have to Sort the columns alphabetically. I believe there's no built in way of doing this, so i'm goign to have to look elsewhere for the task.
I came across This dataTables example, it's pretty awesome but I think I can't give it a List and display the list.
I also came across BalusC's way of incorporating the sorting intot he DataTbal, which is nice, I'm looking for this, but maybe with a jQuery IU.
Is there such an API that can meet my needs? can you point me in the right direction, or do you suggest one? I'd really want one that I just hand over the list in Java, but If I must, I can modify the data to comply with JSON format or some other...
With the native <h:dataTable> you have to do the sorting yourself in your managed bean. You could use existing JSF extension libraries that have them built in such as:
MyFaces Tomahawk - docs
ICEfaces - docs
RichFaces - docs
PrimeFaces - docs
etc, way too many to state.
But if you don't want to use the above toolkits, then in your managed bean, you define your List and sort order (asc or dec). It can be as simple or complex you want.
Change the Ordering library to the SortOrder library, referencing this library: import org.richfaces.component.SortOrder;
The sort order comparator can be defined in a variable programmatically using the <rich:column> attribute:
private SortOrder sorting = SortOrder.unsorted;
This is an example of using SortOrder programmatically using JSF 2.x/RichFaces 4.x. It uses a three-state sort method: unsorted (default), ascending, and descending, and implemented by setting the sortOrder attribute.
Or the comparator default behavior can be overridden in code, as in this example:
#ManagedBean(name="somebean")
#SessionScoped
public class OrderBean implements Serializable {
private static final long serialVersionUID = ....;
private List<Item> items;
private boolean sortAscending;
...
}
In your view, you define the which headers you want to sort with, so add a commandLink to make each header clickable.
<h:dataTable value="#{somebean.items}" var="i">
<h:column>
<f:facet name="header">
<h:commandLink action="#{somebean.sort}"> Sort Column</h:commandLink>
</f:facet>
#{i.name}
</h:column>
</h:dataTable>
Now you have to implement the sort for your bean with basic collections, again, it can be as complex as you can:
private final Comparator NAME_SORT_ASC = new Comparator<Item>() {
#Override
public int compare(Item o1, Item o2) {
return o1.getName().compareTo(o2.getName());
}
}
};
private final Comparator NAME_SORT_DESC = new Comparator<Item>() {
#Override
public int compare(Item o1, Item o2) {
return o2.getName().compareTo(o1.getName());
}
}
};
public String sort() {
Collections.sort(items, sortAscending ? NAME_SORT_ASC : NAME_SORT_DESC );
}
You can make your life easier by reusing stuff instead of doing that for each column, I will let you figure that out. You can use better libraries for Java to help you do the comparator for example with Guava from Google or Collection Commons from Apache.
Instead of doing all that, and reinventing the wheel, use a framework that abstracted all this out for you, they make your life way easier..
There are several component librarys on top of jsf-2.0.
Primefaces for instance has a very powerful datatable component with sorting / filtering options. Primefaces is very easy to integrate into your project and comes with a lot of themes (or you can create your own theme).
Just have a look at the showcase and the documentation.
Other popular component libraries are Richfaces (as per comment datatable sorting not supported) and Icefaces.
You can do it in Richfaces too.
Richfaces 3.3.x supports easy sort:
<rich:column sortable="true" sortBy="#{res.retailerCode}">
<f:facet name="header">
<h:outputText value="#{msg.retailerId}" />
</f:facet>
<h:outputText value="#{res.retailerCode}" />
</rich:column>
In Richfaces 4.x you can sort datatable using Sorting bean:
<rich:column id="cardNumber" sortBy="#{res.instNumber}"
sortOrder="#{cardholderSorting.cardNumberOrder}">
<f:facet name="header">
<a4j:commandLink value="#{msg.cardNumber}"
action="#{cardholderSorting.sortByCardNumber}"
render="cardholderTable" />
</f:facet>
<h:outputText value="#{res.cardNumber}" />
</rich:column>
or your DataModel (extends ExtendedDataModel):
<rich:column id="retailerCode" sortBy="#{rs.retailerCode}" sortOrder="ascending">
<f:facet name="header">
<h:commandLink value="#{msg.retailerId}" style="text-decoration: none; color:black;">
<rich:componentControl target="retailerTable" operation="sort">
<f:param name="column" value="retailerCode" />
<f:param value="" />
<f:param name="reset" value="true" />
</rich:componentControl>
</h:commandLink>
</f:facet>
<h:outputText value="#{rs.retailerCode}" />
</rich:column>
You can add arrows (for sorting order displaying) inside in command link and it will be exact same presentation as in Richfaces 3.3.3.
UPDATE
Starting from RichFaces 4.5 there is support of simple sorting in dataTable (like it was in version 3.3.x).

Recurring JSF problem

I have a recurring JSF problem everytime I output datatables or composite components using ui:repeat. Suppose you are displaying a list of users, and in one column you have 3 icons, one to view the full profile, another to delete the user, and another to edit his data. Since i can't do something like #{fooBean.delete(user)} how should I handle this?
Here's they layout I'm talking about:
http://img821.imageshack.us/img821/9039/tablev.png
I can use commandLink to invoke logic but how do I get the user or article or product etc.
Is there any non-hackish way?
If you're using a dataTable, you can bind the dataTable component to the backing bean and figure out which row was clicked.
<h:dataTable binding="#{backingBean.userTable}" value="#{backingBean.users}" var="user"> ... </h:dataTable>
and
<h:commandLink actionListener="#{backingBean.deleteLinkClicked}">Delete</h:commandLink>
Then the backing bean:
public class BackingBean implements Serializable {
private HtmlDataTable userTable;
// implement getter/setter for userTable
public void deleteLinkClicked(ActionEvent event) {
User user = (User)userTable.getRowData();
// implement code to delete user
}
}
When using ui:repeat, I don't know the best practice, but I've used f:param to pass a parameter in the link. Below is the ui:repeat equivalent of the above.
<ui:repeat value="#{backingBean.users}" var="user">
<h:commandLink value="Delete" action="#{backingBean.deleteUser}">
<f:param name="userId" value="#{user.id}">
</h:commandLink>
</ui:repeat>
In the backing bean:
public class BackingBean implements Serializable {
#ManagedProperty(value="#{param.userId}")
private Long userId;
// implement getter/setter for userId
public String deleteUser() {
// at this point, the userId field should have been set via the param
}
}
I think that you could use an actionListener instead of an action (as I did in the dataTable example), but I haven't tried it.

Categories