jsf - example - primefaces datatable
¿Cómo usar<h: selectBooleanCheckbox> en<h: dataTable> o<ui: repeat> para seleccionar varios elementos? (3)
En el siguiente ejemplo, estoy usando casillas de verificación para seleccionar dos o más productos para permitir al usuario comparar las especificaciones del producto en una nueva página web usando JSF 2.0.
Me tomó un buen tiempo encontrar el siguiente problema (totalmente obvio ahora, por supuesto), por lo que pensé que vale la pena mencionar a los que intentan usar la paginación con el código de BalusC anterior (buena respuesta, BalusC, mucho más simple de lo que nunca imaginé que sería).
Si está utilizando la paginación, obtendrá nullpointers en la línea:
if (checked.get (item.getId ()))
-en el código de BalusC arriba.
Esto se debe a que solo las casillas de verificación mostradas se agregan al mapa (doh; slap fronthead). Para aquellos productos cuyas casillas de verificación nunca se muestran, debido a la paginación, esta línea generará un error de puntero nulo y es necesario agregar una verificación para ignorar estos punteros nulos (asumiendo que todas las casillas de verificación no están marcadas en la carga de la página). Para que el usuario marque una casilla de verificación, debe mostrar la página de paginación, de modo que todo funcione bien después.
Si alguna o todas las casillas de verificación deben estar marcadas en la carga de la primera página, entonces esto no será de ninguna ayuda ... tendrá que agregarlas manualmente al Mapa para que se muestren correctamente en la carga de la página. .
Nota: debido a que estoy usando un objeto JPA ''Clase de entidad de base de datos'', también necesitaba usar @Transient para el ID en mi clase de entidad ProductTbl ya que todas las variables se consideran columnas en la base de datos por JPA, de forma predeterminada, a menos que tengan el prefijo @Transient . También estoy usando un segundo enlace para restablecer las casillas de verificación, que llama a clearSelections (), y mi ''enviar'' es un enlace que llama compareSelectedProducts () en lugar de un botón Enviar.
El código completo es el siguiente:
En la clase de entidad ''ProductTbl'' derivada de la base de datos:
@Transient
private Long id;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
En el bean de respaldo ''ProductSelection'':
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
private String errorMessage = "";
// List of all products.
private List<ProductTbl> products;
// List of products to compare.
private List<ProductTbl> compareProducts;
// Setters and getters for above...
public String compareSelectedProducts()
{
// Reset selected products store.
compareProducts = new ArrayList();
for (ProductTbl item: products)
{
// If there is a checkbox mapping for the current product then...
if(checked.get(item.getId()) != null)
{
// If checkbox is ticked then...
if (checked.get(item.getId()))
{
// Add product to list of products to be compared.
compareProducts.add(item);
}
}
}
if(compareProducts.isEmpty())
{
// Error message that is displayed in the ''ErrorPage.xhtml'' file.
errorMessage = "No Products selected to compare specifications. Select two or more products by ticking the check box in the second column ''Cmpr''";
return "process_ErrorPage";
}
// Rest of code to get product specification data ready to be displayed.
return "process_CompareSelected";
}
public String clearSelections()
{
// Untick all checkbox selections.
checked.clear();
return "process_MainSearchResult";
}
En la página web de JSF ''MainSearchResult.xhtml'':
<h:commandLink action="#{productSelection.compareSelectedProducts()}" value="Cmpr Specification Comparison Table" />
<h:commandLink action="#{productSelection.clearSelections()}" value="Clear Selected" />
<h:dataTable value="#{productSelection.products}" rows="#{productSelection.numberRowsToDisplay}" first="#{productSelection.rowStart}" var="item" headerClass="table-header" >
<h:column>
<f:facet name="header">
<h:outputText style="font-size:12px" value="Cmpr" />
</f:facet>
<div style="text-align:center;" >
<h:selectBooleanCheckbox value="#{productSelection.checked[item.id]}" />
</div>
</h:column>
</h:dataTable>
En el archivo ''faces-config.xml'':
<navigation-rule>
<navigation-case>
<from-outcome>process_MainSearchResult</from-outcome>
<to-view-id>/MainSearchResult.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>process_CompareSelected</from-outcome>
<to-view-id>/CompareSelected.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>process_ErrorPage</from-outcome>
<to-view-id>/ErrorPage.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
Tengo una página de Facelets con una <h:dataTable>
. En cada fila hay un <h:selectBooleanCheckbox>
. Si se selecciona la casilla de verificación, el objeto detrás de la fila correspondiente se debe configurar en el bean.
- ¿Cómo hago esto?
- ¿Cómo obtener las filas seleccionadas o sus datos en un bean de respaldo?
- ¿O sería mejor hacerlo con
<h:selectManyCheckbox>
?
Su mejor apuesta es vincular el valor h:selectBooleanCheckbox
con una propiedad Map<RowId, Boolean>
donde RowId
representa el tipo de identificador de fila. Tomemos un ejemplo de que tienes un objeto Item
cuyo identificador id
propiedad es un Long
:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectBooleanCheckbox value="#{bean.checked[item.id]}" />
</h:column>
...
</h:dataTable>
<h:commandButton value="submit" action="#{bean.submit}" />
que se utiliza en combinación con:
public class Item {
private Long id;
// ...
}
y
public class Bean {
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
private List<Item> items;
public void submit() {
List<Item> checkedItems = checked.entrySet().stream()
.filter(Entry::getKey)
.map(Entry::getValue)
.collect(Collectors.toList());
checked.clear(); // If necessary.
// Now do your thing with checkedItems.
}
// ...
}
Verá, el mapa se rellena automáticamente con la id
de todos los elementos de la tabla como clave y el valor de la casilla de verificación se establece automáticamente como valor de mapa asociado con la id
del elemento como clave.
Una forma de enviar un parámetro a través de <h:selectBooleanCheckbox>
es enviarlo a través del título de la casilla de verificación. En el ValueChangeListener
, puede obtenerlo del componente utilizando un getAttributes().get("title")
. Esto ayuda en los casos en los que desea enviar un valor de ID como parámetro (a diferencia del índice de fila seleccionado).