I'm learning about JSF and am trying to do a tabbed pane following this tutorial:
Tab manager using Ajax and JSF
I have managed to get the tab switch working. Now I want to include a form defined in another XHTML file as tab for this tabbed pane in which there's a dataTable
with a commandButton
to delete the selected row, called clientes.xhtml
. If I navigate directly to this page then delete button works as expected. But when I include this page within contentForm
it shows as expected but delete button doesn't do what is supposed to do, it just refresh the current page but no row is deleted.
This is what I have so far:
welcome.xhtml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns="http://www.w3.org/1999/xhtml"
template="./templates/BasicTemplate.xhtml">
<ui:define name="menu_bar">
<h:form id="formMenu">
<ul id="menu-list">
<li><h:commandLink value="Home">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(0)}" />
</h:commandLink></li>
<li><h:commandLink value="Clientes">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(1)}" />
</h:commandLink></li>
<li><h:commandLink value="Proveedores">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(2)}" />
</h:commandLink></li>
</ul>
</h:form>
</ui:define>
<ui:define name="content">
<h:form id="contentForm">
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 0}">
<h1>Hi there!</h1>
<hr />
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<ui:include src="clientes.xhtml" />
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 2}">
<ui:include src="proveedores.xhtml" />
</h:panelGroup>
</h:form>
</ui:define>
</ui:composition>
clientes.xhtml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns="http://www.w3.org/1999/xhtml">
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<h:column>
<f:facet name="header">
<h:outputText value="Id" />
</f:facet>
<h:outputText value="#{cliente.idCliente}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Fecha de ingreso" />
</f:facet>
<h:outputText value="#{cliente.fechaIngreso}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Nombre" />
</f:facet>
<h:outputText value="#{cliente.nombre}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Domicilio" />
</f:facet>
<h:outputText value="#{cliente.domicilio}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Teléfono" />
</f:facet>
<h:outputText value="#{cliente.telefono}" />
</h:column>
<h:column>
<f:facet name="header" />
<h:commandButton image="./resources/css/delete_16.png" action="#{clientesManagedBean.eliminarCliente(cliente)}"/>
</h:column>
</h:dataTable>
</h:form>
</ui:composition>
Edit 1
Here is the ClientesManagedBean
code:
ClientesManagedBean.java
import beans.interfaces.IClientesBeanLocal;
import domain.entities.ClienteJpa;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.view.ViewScoped;
@ManagedBean
@ViewScoped
public class ClientesManagedBean {
@EJB(beanName = "ClientesBeanJpa")
private IClientesBeanLocal clientesBeanLocal;
private List<ClienteJpa> listaClientes;
private ClienteJpa cliente;
@PostConstruct
public void init() {
listaClientes = new ArrayList<>();
listaClientes.addAll(clientesBeanLocal.getTodos());
}
public List<ClienteJpa> getListaClientes() {
return listaClientes;
}
public ClienteJpa getCliente() {
return cliente;
}
public void eliminarCliente(ClienteJpa cliente) {
if(clientesBeanLocal.eliminar(cliente) == IClientesBeanLocal.EXITO) {
listaClientes.remove(cliente);
}
}
}
And ClientesBeanJpa
session bean, just in case:
ClientesBeanJpa.java
import beans.interfaces.IClientesBeanLocal;
import domain.entities.ClienteJpa;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless(name = "ClientesBeanJpa")
public class ClientesBeanJpa implements IClientesBeanLocal {
@PersistenceContext(unitName = "CursoJ2eePU")
private EntityManager entityManager;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public int eliminar(ClienteJpa cliente) {
if(entityManager == null) {
String error = "Error al inyectar EntityManager en la clase " + getClass().getCanonicalName();
throw new ExceptionInInitializerError(error);
} else {
ClienteJpa clienteAEliminar = entityManager.getReference(ClienteJpa.class, cliente.getIdCliente());
entityManager.remove(clienteAEliminar);
return EXITO;
}
}
}
Edit 2
Based on @Luiggi's suggestion I've tested if ClientesManagedBean#eliminar(cliente)
method is even called and I've found this out:
- If
tabIndex
property is set to1
by default, thenclientes.xhtml
is rendered and it works as expected. - If
tabIndex
property is set to another value and then navigate to tab 1, theneliminar(cliente)
is not even called.
Including TabViewManagedBean
code just in case.
TabViewManagedBean.java
import javax.faces.bean.ManagedBean;
import javax.faces.view.ViewScoped;
@ManagedBean
@ViewScoped
public class TabViewManagedBean {
private Integer tabIndex = 0;
/*
* If I set tabIndex to 1 then clientes.xhtml is rendered by default
* and everithing works as expected.
* But if I set this property to 0 and then navigate to tab 1 then it
* behaves as described.
*/
public TabViewManagedBean() {
super();
}
public Integer getTabIndex() {
return tabIndex;
}
public void setTabIndex(Integer tabIndex) {
this.tabIndex = tabIndex;
}
}