我正在学习JSF,并且正在尝试按照本教程进行选项卡式窗格:
Tab manager using Ajax and JSF
我设法让标签开关工作。现在,我想将另一个XHTML文件中定义的表单作为此选项卡式窗格的选项卡包含在其中,dataTable
带有commandButton
以删除所选行,称为clientes.xhtml
。如果我直接导航到此页面,则删除按钮按预期工作。但是当我在contentForm
中包含此页面时,它会按预期显示但删除按钮不会执行应该执行的操作,它只刷新当前页面但不删除任何行。
这是我到目前为止所做的:
<?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>
<?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>
以下是ClientesManagedBean
代码:
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);
}
}
}
和ClientesBeanJpa
会话bean,以防万一:
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;
}
}
}
根据@Luiggi的建议,我测试了ClientesManagedBean#eliminar(cliente)
方法是否被调用,我发现了这一点:
tabIndex
属性设置为1
,则会呈现clientes.xhtml
并按预期工作。tabIndex
属性设置为其他值,然后导航到选项卡1,则甚至不会调用eliminar(cliente)
。包含TabViewManagedBean
代码以防万一。
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;
}
}
答案 0 :(得分:3)
问题是您正在嵌套<form>
,这是无效的HTML。这可以通过以下代码注意到:
welcome.xhtml:
<ui:define name="content">
<h:form id="contentForm">
<!-- code here... -->
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<!-- including source of clientes.xhtml page -->
<ui:include src="clientes.xhtml" />
</h:panelGroup>
<!-- code here... -->
</h:form>
</ui:define>
在clientes.xhtml中你有:
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<!-- more code... -->
</h:dataTable>
<h:form>
以这种方式结束:
<h:form id="contentForm">
<!-- code here... -->
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<!-- more code... -->
</h:dataTable>
<h:form>
</h:panelGroup>
<!-- code here... -->
</h:form>
决定将<h:form>
定义为没有嵌套表单的位置。 IMO你应该在最窄的范围内定义<h:form>
,在这种情况下,它只在clientex.xhtml页面中(以及要包含的页面中)。
更多信息: