使用ajax包含XHTML文件时的表单行为

时间:2014-06-24 21:03:44

标签: jsf jsf-2

我正在学习JSF,并且正在尝试按照本教程进行选项卡式窗格:

Tab manager using Ajax and JSF

我设法让标签开关工作。现在,我想将另一个XHTML文件中定义的表单作为此选项卡式窗格的选项卡包含在其中,dataTable带有commandButton以删除所选行,称为clientes.xhtml。如果我直接导​​航到此页面,则删除按钮按预期工作。但是当我在contentForm中包含此页面时,它会按预期显示但删除按钮不会执行应该执行的操作,它只刷新当前页面但不删除任何行。

这是我到目前为止所做的:

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>

编辑1

以下是ClientesManagedBean代码:

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);
        }
    }

}

ClientesBeanJpa会话bean,以防万一:

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;
        }
    }
}

编辑2

根据@Luiggi的建议,我测试了ClientesManagedBean#eliminar(cliente)方法是否被调用,我发现了这一点:

  • 如果默认情况下tabIndex属性设置为1,则会呈现clientes.xhtml并按预期工作。
  • 如果tabIndex属性设置为其他值,然后导航到选项卡1,则甚至不会调用eliminar(cliente)

包含TabViewManagedBean代码以防万一。

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;
    }

}

1 个答案:

答案 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页面中(以及要包含的页面中)。

更多信息: