Selección múltiple de filas en un datatable con JSF: haciendo uso de librerías de componentes.

1
19505

Selección múltiple de filas en un datatable con JSF: haciendo uso de librerías de componentes.

0. Índice de contenidos.


1. Introducción

En este tutorial vamos a analizar las opciones que tenemos disponibles en JSF para mostrar e interactuar con una tabla de datos que permita una selección múltiple de filas.

La historia de usuario que perseguimos sería similar a esta: Como Pablo quiero marcar como pagada más de una factura a la vez,
directamente desde la interfaz de búsqueda, para ahorrarme el trabajo de editarlas una a una
. Pablo es miembro del departamento financiero de nuestro hipotético cliente.

No es requisito del usuario, pero sí objetivo del tutorial, recibir un evento de selección de fila en el servidor para actualizar un listado de filas seleccionadas en el cliente
con el soporte de Ajax.

Para ello vamos a revisar las opciones que tenemos disponibles en el mercado usando las librerías de componentes visuales con las que nosotros trabajamos habitualmente.


2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 17′ (2.93 GHz Intel Core 2 Duo, 4GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.1
  • JSF 1.2 (Mojarra 1.2_12) o 2 (Mojarra 2.0.4)
  • ICEfaces 2.0
  • Primefaces 2.1
  • RichFaces 3.3
  • Apache Tomcat 7.0.6


3. Nuestra «capa de servicios».

La información que vamos a mostrar en la tabla de datos son facturas con lo que primero necesitamos una entidad que represente dicha información, para el objetivo de este tutorial,
la entidad no tendrá el soporte de ninguna tecnología de persistencia, será un POJO que bien podría ser un DTO usado solo para vista.

package com.autentia.jsf.showcase.core;

import java.io.Serializable;
import java.math.BigDecimal;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

public class Invoice implements Serializable {

	private static final long serialVersionUID = 4721689590234569551L;

	private String number;
	private String client;
	private BigDecimal amount;
	private boolean invoiced;
	
	public Invoice(String number, String client,
			BigDecimal amount) {
		this.number = number;
		this.client = client;
		this.amount = amount;
	}

	public String getNumber() {
		return number;
	}

	public String getClient() {
		return client;
	}

	public Object getAmount() {
		return amount;
	}


	public void setInvoiced(boolean invoiced) {
		this.invoiced = invoiced;
	}

	public boolean isInvoiced() {
		return invoiced;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		try {
			final Invoice other = (Invoice)obj;
			final EqualsBuilder equalsBuilder = new EqualsBuilder();
			equalsBuilder.append(this.number, other.number);
			return equalsBuilder.isEquals();
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public int hashCode() {
		final HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
		hashCodeBuilder.append(number);
		return hashCodeBuilder.toHashCode();
	}

}


Para dar soporte a la recuperación de facturas así como al cambio de estado de las mismas a facturado, vamos a apoyarnos en un servicio como el siguiente:

package com.autentia.jsf.showcase.core;

import java.util.ArrayList;
import java.util.List;

public class FinancialService {
	
	private static final FinancialService instance = new FinancialService();

	private List<Invoice> invoices = new ArrayList<Invoice>();
	
	private FinancialService() {
	}

	public static FinancialService getInstance() {
		return instance;
	}

	public void add(Invoice invoice) {
		invoices.add(invoice);
	}

	public List<Invoice> getAll() {
		return invoices;
	}

	public void markAsInvoiced(Invoice invoice) {
		invoice.setInvoiced(true);
		invoices.set(invoices.indexOf(invoice), invoice);
	}
	
	public void markAsInvoiced(List<Invoice> invoices) {
		for (Invoice invoice : invoices) {
			markAsInvoiced(invoice);
		}
	}

}

Se trata de un singleton de aplicación que hemos creado con el soporte de una
plantilla de Elcipse.

El servicio y el POJO serán comunes para todos los dataTables que vamos a evaluar, así como la siguiente clase de utilidades para poblar el listado de facturas en nuestros ejemplos.

package com.autentia.jsf.showcase.core;

import java.math.BigDecimal;

public class AddSampleData {

	public static void initializeInvoices(){
		for (int i = 0; i < 49; i++) {
			FinancialService.getInstance().add(new Invoice("11/0000"+i,"Årea de Negocio" +i,BigDecimal.valueOf(1320.69 + i)));	
		}
	}

}


4. <ice:dataTable de ICEfaces.

El primer componente que vamos a analizar es el datatable de ICEfaces, ahora en su versión 2.0. Para conseguir selección múltiple de filas nos tenemos que apoyar
en el componente ice:rowSelector asignando a su atributo multiple a true.

	
    <ice:form id="iceForm">

       <ice:panelGroup>

					<ice:dataTable id="invoicesList"
	                       var="invoice"
	                       value="#{invoiceView.invoices}"
	                       rows="10">
			            <ice:column>
							
			                <ice:rowSelector id="selected"
			                                 value="#{invoiceView.mapOfInvoicesSelected[invoice]}"
			                                 multiple="true"
			                                 enhancedMultiple="true"                                 
			                                 preStyleOnSelection="true"
			                                 selectionListener="#{invoiceView.rowSelectionListener}"
			                                 />
			                
			                <f:facet name="header">
			                    <ice:outputText id="number_label"
			                                    value="#{msg['Invoice.number']}"/>
			                </f:facet>
			                <ice:outputText id="number"
			                                value="#{invoice.number}"/>
			            </ice:column>
			
			            <ice:column>
			                <f:facet name="header">
			                    <ice:outputText id="client_label"
			                                    value="#{msg['Invoice.client']}"/>
			                </f:facet>
			                <ice:outputText id="label"
			                                value="#{invoice.client}"/>
			            </ice:column>
			
			            <ice:column>
			                <f:facet name="header">
			                    <ice:outputText id="amount_label"
			                                    value="#{msg['Invoice.amount']}"/>
			                </f:facet>
			                <ice:outputText id="amount"
			                                value="#{invoice.amount}"/>
			            </ice:column>
			            
			            <ice:column>
			                <f:facet name="header">
			                    <ice:outputText id="invoiced_label"
			                                    value="#{msg['Invoice.invoiced']}"/>
			                </f:facet>
			                <ice:outputText id="invoiced"
			                                value="#{invoice.invoiced}"/>
			            </ice:column>
			        </ice:dataTable>
			        <ui:decorate template="/WEB-INF/includes/paginator.jspx">
						<ui:param name="dataTableId" value="invoicesList" />
					</ui:decorate>
					<ice:panelGroup>
						<ice:commandButton actionListener="#{invoiceView.markAsInvoicedListener}" value="#{msg['components.datatableMultipleSelection.bill']}"/>
					</ice:panelGroup>					
				</ice:panelGroup>

				<ice:panelGroup>
					<hr />
					<h:outputText value="#{msg['components.datatableMultipleSelection.selectedInvoices']}" />
					<ul>
						<ui:repeat var="invoice" value="#{invoiceView.invoicesSelected}" >
							<li><h:outputText value="#{invoice.number} - #{invoice.client} - #{invoice.amount}" /></li>
						</ui:repeat>
					</ul>
				</ice:panelGroup>
				
     </ice:form>
    

La parametrización es simple aún introduciendo dicho componente ice:rowSelector, que es el mismo componente que para la selección única, y lo que hemos hecho (a
diferencia del ejemplo que se propone en la component suite de ICEfaces) es obtener el valor de seleccionado (si|no) de un mapa en el controlador en vez de en un
booleano en el propio POJO, con ello nos evitamos recorrernos todas las facturas cada vez que seleccionamos.

El soporte del lado del managedBean es el siguiente:

package com.autentia.jsf.showcase.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.autentia.jsf.showcase.core.AddSampleData;
import com.autentia.jsf.showcase.core.Invoice;
import com.autentia.jsf.showcase.core.FinancialService;
import com.icesoft.faces.component.ext.RowSelectorEvent;

@ManagedBean
@ViewScoped
public class InvoiceView implements Serializable{

	private static final long serialVersionUID = 5587527957231937424L;

	private static final Log log = LogFactory.getLog(InvoiceView.class);
	
	private List<Invoice> invoices;
	
  private Map<Invoice,Boolean> mapOfInvoicesSelected;
    
	@PostConstruct
	protected void init(){
		log.trace("init...");
		AddSampleData.initializeInvoices();
		clearSelectedInvoices();
	}
	
	private void clearSelectedInvoices(){
		mapOfInvoicesSelected = new HashMap<Invoice, Boolean>();
	}
	
	public List<Invoice> getInvoices(){
		if (invoices == null){
			invoices = FinancialService.getInstance().getAll();
		}
		log.trace("allInvoices: " + invoices);
		return invoices;
	}
	
	public List<Invoice> getInvoicesSelected(){
		log.trace("selectedInvoices? " + mapOfInvoicesSelected);
		return new ArrayList<Invoice>(mapOfInvoicesSelected.keySet());
	}
	
	public Map<Invoice,Boolean> getMapOfInvoicesSelected() {
		return mapOfInvoicesSelected;
	}
	
  public void rowSelectionListener(RowSelectorEvent event) {
    log.trace("row selection " + event.getRow());
    mapOfInvoicesSelected.put(getInvoices().get(event.getRow()), Boolean.valueOf(event.isSelected()));  	
  }
    
  public void markAsInvoicedListener(ActionEvent event){
  final List<Invoice> invoicesSelected = getInvoicesSelected();
		log.trace("markAsInvoicedListener " + invoicesSelected);
    FinancialService.getInstance().markAsInvoiced(invoicesSelected);
    clearSelectedInvoices();
  }
    
}

Para manejar el evento de selección vía Ajax no tenemos que hacer nada en especial, entra en juego el Direct-to-DOM de ICEfaces y, a través del partialSubmit,
implícito en el dataTable los eventos se envían al managedBean vía Ajax.

El controlador maneja dos eventos de la vista:

  • la selección de fila que recibe un objeto de tipo RowSelectorEvent, propio de ICEfaces, que tiene el índice de la fila seleccionada y nos indica si ha sido seleccionado o no,
  • la pulsación sobre el botón de «facturar» que cambia el estado de las facturas a facturadas,

El resultado a nivel de interfaz visual es el siguiente:

ice:dataTable ICEfaces

Permite la selección múltiple de filas pulsando sobre las mismas manteniendo el CTRL en windows y el CMD en mac. Con el atributo enhancedMultiple=true te permite moverte con los cursores por el listado y seleccionar usando SHIFT.

Inconvenientes:

  • la interfaz trata de emular los listados tipo windows, en los que accedes al contenido de los registros del listado con un doble-click, si quieres programar el
    acceso al detalle de la factura tendrás que ir por esa vía o incluir un icono para acceder al detalle,
  • la selección no es intuitiva, tendríamos que poner una leyenda para que el usuario supiera que ese listado admite selección múltiple,
  • no tiene opción de selección de todos o ninguno, la tendríamos que hacer a mano,
  • no termina de funcionar la opción de deselección, ni aún incluyendo en el evento de selección el hecho de encolarlo hasta la fase de INVOKE_APPLICATION
    (algo que se recomienda bastante en el foro de ICEfaces, no solo para este evento sino para todos, en cuanto no se puede recuperar el valor de un componente).

5. <rich:extendedDataTable de RichFaces.

El dataTable de RichFaces no soporta por sí mismo selección múltiple, para hacer uso de la misma tenemos que usar el componente extendido <rich:extendedDataTable

     <a4j:form id="richForm">

					<rich:extendedDataTable id="invoicesList"
	                       var="invoice"
	                       value="#{invoiceView.invoices}"
	                       rows="10"
	                       selectionMode="multi"
	                       selection="#{invoiceView.invoicesSelection}"
	                       height="250px"
	                       >
				       <a4j:support event="onselectionchange" reRender="selectedInvoicesPanel" requestDelay="400"
				            	action="#{invoiceView.takeSelection}" ajaxSingle="true" />
       
			            <rich:column>
			                <f:facet name="header">
			                    <h:outputText id="number_label"
			                                    value="#{msg['Invoice.number']}"/>
			                </f:facet>
			                <h:outputText id="number"
			                                value="#{invoice.number}"/>
			            </rich:column>
			
			            <rich:column>
			                <f:facet name="header">
			                    <h:outputText id="client_label"
			                                    value="#{msg['Invoice.client']}"/>
			                </f:facet>
			                <h:outputText id="label"
			                                value="#{invoice.client}"/>
			            </rich:column>
			
			            <rich:column>
			                <f:facet name="header">
			                    <h:outputText id="amount_label"
			                                    value="#{msg['Invoice.amount']}"/>
			                </f:facet>
			                <h:outputText id="amount"
			                                value="#{invoice.amount}"/>
			            </rich:column>
			            
			            <rich:column>
			                <f:facet name="header">
			                    <h:outputText id="invoiced_label"
			                                    value="#{msg['Invoice.invoiced']}"/>
			                </f:facet>
			                <h:outputText id="invoiced"
			                                value="#{invoice.invoiced}"/>
			            </rich:column>
			        </rich:extendedDataTable>
			        <ui:decorate template="/WEB-INF/includes/paginator.jspx">
						<ui:param name="dataTableId" value="invoicesList" />
					</ui:decorate>
            
					<h:panelGroup>
						<h:commandButton actionListener="#{invoiceView.markAsInvoicedListener}" value="#{msg['components.datatableMultipleSelection.bill']}"/>
					</h:panelGroup>					

				<h:panelGroup id="selectedInvoicesPanel">
					<hr />
					<h:outputText value="#{msg['components.datatableMultipleSelection.selectedInvoices']}" />
					<ul>
						<ui:repeat var="invoice" value="#{invoiceView.invoicesSelected}" >
							<li><h:outputText value="#{invoice.number} - #{invoice.client} - #{invoice.amount}" /></li>
						</ui:repeat>
					</ul>
				</h:panelGroup>
				
     </a4j:form>

El componente de RichFaces dispone de un atributo selectionMode=»multi», para indicar que la selección es múltiple y mediante el atributo selection, vía EL, indicamos
una colección en el ManagedBean en la que se almacenarán las facturas seleccionadas.

Para manejar el evento de selección vía Ajax hacemos uso de un componente del tipo <a4j:support event=»onselectionchange», el evento en el managedBean no hace nada, simplemente a través del atributo
reRender=»selectedInvoicesPanel» indicamos que queremos rerenderizar el listado de facturas seleccionadas en la vista.

El soporte del lado del managedBean es el siguiente:

package com.autentia.jsf.showcase.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.event.ActionEvent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.model.selection.Selection;

import com.autentia.jsf.showcase.core.AddSampleData;
import com.autentia.jsf.showcase.core.FinancialService;
import com.autentia.jsf.showcase.core.Invoice;

public class InvoiceView implements Serializable{

	private static final long serialVersionUID = 5587527957231937424L;

	private static final Log log = LogFactory.getLog(InvoiceView.class);
	
	private List<Invoice> invoices;
	
  private Selection invoicesSelection;
    
	@PostConstruct
	protected void init(){
		log.trace("init...");
		AddSampleData.initializeInvoices();
	}
	
	public List<Invoice> getInvoices(){
		if (invoices == null){
			invoices = FinancialService.getInstance().getAll();
		}
		log.trace("allInvoices: " + invoices);
		return invoices;
	}
	
	public Selection getInvoicesSelection(){
		return invoicesSelection;
	}
	
	public void setInvoicesSelection(Selection selection){
		this.invoicesSelection = selection;
	}
	
	public List<Invoice> getInvoicesSelected(){
		final List<Invoice> invoices = new ArrayList<Invoice>();
		if (invoicesSelection != null){
			final Iterator<Object> invoicesToIterate = invoicesSelection.getKeys();
			log.trace("selectedInvoices? " + invoicesToIterate);
			while(invoicesToIterate.hasNext()){
				invoices.add(getInvoices().get((Integer) invoicesToIterate.next()));
			}
		}
		log.trace("invoices " + invoices);
		return invoices;
	}
	
	public void takeSelection(){
		log.trace("takeSelection " + invoicesSelection.getKeys());
	}
    public void markAsInvoicedListener(ActionEvent event){
    	final List<Invoice> invoicesSelected = getInvoicesSelected();
		log.trace("markAsInvoicedListener " + invoicesSelected);
    	FinancialService.getInstance().markAsInvoiced(invoicesSelected);
    }
    
}

Para conocer el listado de facturas seleccionadas hacemos uso del componente Selection propio de RichFaces.

El resultado a nivel de interfaz visual es el siguiente:

ice:extendedDataTable RichFaces

Permite la selección múltiple de filas pulsando sobre las mismas manteniendo el CTRL en windows y en mac también con lo que se hace bastante incómodo, puesto que levanta el menú contextual. Funciona con el SHIFT y el ratón o los cursores.

Inconvenientes:

  • al igual que ICEfaces, la interfaz trata de emular los listados tipo windows, en los que accedes al contenido de los registros del listado con un doble-click, si quieres programar el
    acceso al detalle de la factura tendrás que ir por esa vía o incluir un icono para acceder al detalle,
  • la selección no es intuitiva, tendríamos que poner una leyenda para que el usuario supiera que ese listado admite selección múltiple,
  • no tiene opción de selección de todos o ninguno, la tendríamos que hacer a mano,

6. Primefaces.

Primefaces soporta selección múltiple en su datatable de dos maneras distintas, como la hemos visto hasta ahora y con un componente embebido que añade unas casillas
de verificación.

Veamos primero la opción correlativa a las que hemos visto hasta ahora:

  <h:form id="pForm">

      <h:panelGroup>

					<p:dataTable id="invoicesList"
	                       var="invoice"
	                       value="#{invoiceView.invoices}"
	                       rows="10"
	                       selectionMode="multiple"
	                       selection="#{invoiceView.invoicesSelected}"
	                       update="selectedInvoicesPanel"
	                       paginator="true" >
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="number_label"
			                                    value="#{msg['Invoice.number']}"/>
			                </f:facet>
			                <h:outputText id="number"
			                                value="#{invoice.number}"/>
			            </p:column>
			
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="client_label"
			                                    value="#{msg['Invoice.client']}"/>
			                </f:facet>
			                <h:outputText id="label"
			                                value="#{invoice.client}"/>
			            </p:column>
			
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="amount_label"
			                                    value="#{msg['Invoice.amount']}"/>
			                </f:facet>
			                <h:outputText id="amount"
			                                value="#{invoice.amount}"/>
			            </p:column>
			            
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="invoiced_label"
			                                    value="#{msg['Invoice.invoiced']}"/>
			                </f:facet>
			                <h:outputText id="invoiced"
			                                value="#{invoice.invoiced}"/>
			            </p:column>

			        </p:dataTable>
					<h:panelGroup>
						<h:commandButton actionListener="#{invoiceView.markAsInvoicedListener}" value="#{msg['components.datatableMultipleSelection.bill']}"/>
					</h:panelGroup>					
				</h:panelGroup>

				<h:panelGroup id="selectedInvoicesPanel">
					<hr />
					<h:outputText value="#{msg['components.datatableMultipleSelection.selectedInvoices']}" />
					<ul>
						<ui:repeat var="invoice" value="#{invoiceView.invoicesSelected}" >
							<li><h:outputText value="#{invoice.number} - #{invoice.client} - #{invoice.amount}" /></li>
						</ui:repeat>
					</ul>
				</h:panelGroup>
				
	</h:form>

Similar al componente de RichFaces, el componente de PrimeFaces dispone de un atributo selectionMode=»multiple», para indicar que la selección es múltiple y
mediante el atributo selection, vía EL, indicamos una colección en el ManagedBean en la que se almacenarán las facturas seleccionadas.

Para manejar el evento de selección vía Ajax hacemos uso del atributo update donde indicamos el id de la lista que queremos rerenderizar.

El soporte del lado del managedBean es el siguiente:

package com.autentia.jsf.showcase.view;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

import org.apache.log4j.Logger;

import com.autentia.jsf.showcase.core.AddSampleData;
import com.autentia.jsf.showcase.core.Invoice;
import com.autentia.jsf.showcase.core.FinancialService;

@ManagedBean
@ViewScoped
public class InvoiceView implements Serializable{

	private static final long serialVersionUID = 5587527957231937424L;

	private static final Logger log = Logger.getLogger(InvoiceView.class.getName());
	
	private List<Invoice> invoices;
	
	private Invoice[] invoicesSelected; 
    
	@PostConstruct
	protected void init(){
		log.debug("init...");
		AddSampleData.initializeInvoices();
	}
	
	public void setInvoicesSelected(Invoice[] invoicesSelected) {
		this.invoicesSelected = invoicesSelected;
	}


	public Invoice[] getInvoicesSelected() {
		return invoicesSelected;
	}
	
	public List<Invoice> getInvoices(){
		if (invoices == null){
			invoices = FinancialService.getInstance().getAll();
		}
		log.debug("allInvoices: " + invoices);
		return invoices;
	}
	
    public void markAsInvoicedListener(ActionEvent event){
    	final List<Invoice> invoicesSelected = Arrays.asList(getInvoicesSelected());
		log.debug("markAsInvoicedListener " + invoicesSelected);
    	FinancialService.getInstance().markAsInvoiced(invoicesSelected);    	
    }
    
}

A diferencia de RichFaces o ICEfaces aquí no tenemos la necesidad de trabajar con objeto de la librería, la selección la tenemos directamente en un Array.

El resultado a nivel de interfaz visual es el siguiente:

p:dataTable PrimeFaces

Permite la selección múltiple de filas pulsando sobre las mismas no funciona vía CTRL, ni CMD o SHIFT.

La otra opción es hacer uso del atributo selectioMode=»multiple» en un componente p:column

		<h:form id="pForm">

			 <h:panelGroup>

					<p:dataTable id="invoicesList"
	                       var="invoice"
	                       value="#{invoiceView.invoices}"
	                       rows="10"
	                       selection="#{invoiceView.invoicesSelected}"
	                       paginator="true" >
	                    	                    
						<p:column selectionMode="multiple" />  

			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="number_label"
			                                    value="#{msg['Invoice.number']}"/>
			                </f:facet>
			                <h:outputText id="number"
			                                value="#{invoice.number}"/>
			            </p:column>
			
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="client_label"
			                                    value="#{msg['Invoice.client']}"/>
			                </f:facet>
			                <h:outputText id="label"
			                                value="#{invoice.client}"/>
			            </p:column>
			
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="amount_label"
			                                    value="#{msg['Invoice.amount']}"/>
			                </f:facet>
			                <h:outputText id="amount"
			                                value="#{invoice.amount}"/>
			            </p:column>
			            
			            <p:column>
			                <f:facet name="header">
			                    <h:outputText id="invoiced_label"
			                                    value="#{msg['Invoice.invoiced']}"/>
			                </f:facet>
			                <h:outputText id="invoiced"
			                                value="#{invoice.invoiced}"/>
			            </p:column>

			        </p:dataTable>
					<h:panelGroup>
						<h:commandButton actionListener="#{invoiceView.markAsInvoicedListener}" value="#{msg['components.datatableMultipleSelection.bill']}"/>
					</h:panelGroup>					
				</h:panelGroup>

				<p:panel id="selectedInvoicesPanel" widgetVar="selectedInvoicesPanel"
					header="#{msg['components.datatableMultipleSelection.selectedInvoices']}">
					<ul>
						<ui:repeat var="invoice" value="#{invoiceView.invoicesSelected}" >
							<li><h:outputText value="#{invoice.number} - #{invoice.client} - #{invoice.amount}" /></li>
						</ui:repeat>
					</ul>
				</p:panel>
				
		</h:form>

El resultado a nivel de interfaz visual es el siguiente:

p:dataTable PrimeFaces checkboxes

El soporte del lado del managedBean es el mismo.

Inconvenientes:

  • con la primera opción, los mismos inconvenientes que con el resto de librerías,
  • con la segunda opción (la de los checkboxes), que no podemos gestionar el evento de selección en el managedBean, aunque esto puede que no sea un inconveniente para todo el mundo


7. Referencias.


8. Conclusiones.

Sea cual sea la librería de componentes con la que trabajes, seguro que habrá algún motivo por el cuál, alguna vez, no cubra todas tus necesidades. Esta es la razón
por la cuál debes adquirir el conocimiento suficiente para extender dicha funcionalidad, ya sea con un componente nativo, extendido el de la librería que uses o con
un componente de facelets.

Con ello, si no dispones de una librería de componentes que te de soporte a la
selección múltiple en un dataTable,
hazlo tú mismo!.

Un saludo.

Jose

jmsanchez@autentia.com

1 COMENTARIO

  1. Hola, gracias por este ejemplo. Le tengo una pregunta me gustaría aprender como hacer una datatable que agrupe por una columna y el subtable o grupo de filas sea una lista con checkbox para seleccionar de cada item. Saludos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad