1

我有一个带有 2 个单选按钮的表单:“type1”和“type2”。如果选择“type1”,则必须显示下拉菜单。如果选择“type2”,则必须显示文本字段。

这是视图和控制器:

test.xtml

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:rich="http://richfaces.org/rich"
            xmlns:a4j="http://richfaces.org/a4j">


    <h:form>

        <h:selectOneRadio 
            id="type"
            label="Type"
            value="#{testBean.type}">
            <f:selectItem itemLabel="Type1" itemValue="type1" />
            <f:selectItem itemLabel="Type2" itemValue="type2" />
            <f:ajax execute="@all" render="selectBox inputBox"/>
        </h:selectOneRadio>

        <h:selectOneMenu
            id="selectBox"
            label="Service"
            value="#{testBean.service}"
            rendered="#{testBean.isType1}"
            style="width:285px">
            <f:selectItem itemLabel="Medium"  itemValue="medium" />
            <f:selectItem itemLabel="Basic"   itemValue="basic" />
            <f:selectItem itemLabel="Premium" itemValue="premium" />
        </h:selectOneMenu>
        <h:inputText 
            id="inputBox"
            size="50"
            value="#{testBean.custom}"
            rendered="#{!testBean.isType1}" />

    </h:form>

</ui:composition>

TestBean.java

package com.test.backing;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name = "testBean")
@SessionScoped
public class TestBean implements Serializable
{
private static final long serialVersionUID = -4337084623546767911L;

private String type = "type1";
private String service;
private String custom;

public Boolean getIsType1()
{
    if(type.equals("type1"))
    {
        System.out.println(type+":true");
        return true;
    }
    else
    {
        System.out.println(type+":false");
        return false;
    }
}

public String getType()
{
    return type;
}
public void setType(String type)
{
    this.type = type;
}

public String getService()
{
    return service;
}

public void setService(String service)
{
    this.service = service;
}

public String getCustom()
{
    return custom;
}

public void setCustom(String custom)
{
    this.custom = custom;
}

}

当我启动我的应用程序时,我的标准输出中有以下内容:

type1:true
type1:true
type1:true
type1:true
type1:true
type1:true

但是,当我选择另一种类型时,UI 中没有任何反应。这是如何引起的,我该如何解决?

4

2 回答 2

4

JSF 生成 HTML。JS/Ajax 适用于 HTML。JS/Ajax 通过在 HTML DOM 树中查找 HTML 元素document.getElementById()并根据 Ajax 响应替换其内容来更新 HTML 元素。但是,如果一个 JSF 组件被指示不呈现 HTML,那么 JS/Ajax 就无法在 HTML DOM 树中找到它,因此无法替换任何东西。

您只能对始终呈现的 JSF 组件的 HTML 表示进行 ajax 更新。因此,将它们包装在例如 a<h:panelGroup>中。

<h:selectOneRadio ...> 
    <f:ajax ... render="selectAndInputBox" />
</h:selectOneRadio>
<h:panelGroup id="selectAndInputBox">
    <h:selectOneMenu ... rendered="..." />
    <h:inputText ... rendered="..." />
</h:panelGroup>

也可以看看:


与具体问题无关,这种getIsType1()方法很笨拙。只需直接在视图中进行比较即可摆脱它。

<h:selectOneMenu ... rendered="#{testBean.type == 'type1'}" />
<h:inputText ... rendered="#{testBean.type != 'type1'}" />

或者,更符合您最初的问题,

<h:selectOneMenu ... rendered="#{testBean.type == 'type1'}" />
<h:inputText ... rendered="#{testBean.type == 'type2'}" />
于 2013-04-11T14:48:14.330 回答
4

尝试用以下代码替换 xhtml 代码

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:rich="http://richfaces.org/rich"
            xmlns:a4j="http://richfaces.org/a4j">

<h:head>

</h:head>

<h:form prependId="false">

    <h:selectOneRadio 
        id="type"
        label="Type"
        value="#{testBean.type}">
        <f:selectItem itemLabel="Type1" itemValue="type1" />
        <f:selectItem itemLabel="Type2" itemValue="type2" />
        <f:ajax execute="@all" render="selectInputPanel"/>
    </h:selectOneRadio>
    <h:panelGroup id="selectInputPanel">
    <h:selectOneMenu
        id="selectBox"
        label="Service"
        value="#{testBean.service}"
        rendered="#{testBean.isType1}"
        style="width:285px">
        <f:selectItem itemLabel="Medium"  itemValue="medium" />
        <f:selectItem itemLabel="Basic"   itemValue="basic" />
        <f:selectItem itemLabel="Premium" itemValue="premium" />
    </h:selectOneMenu>
    <h:inputText 
        id="inputBox"
        size="50"
        value="#{testBean.custom}"
        rendered="#{!testBean.isType1}" />
    </h:panelGroup>
</h:form></ui:composition>

您的代码中的主要问题是,

  1. 缺少 h:head 以导入 jsf ajax 所需的 jsf.js。
  2. 请按照@BaluC 的建议将您的组件包装到一个 panelGroup 中,因为一旦组件未呈现(页面上不可用),那么其上的 ajax 将无法使用其 ID。

关于 getIsType1() 方法调用的次数是由于渲染属性,有关更多信息,请在此处查看@Baluc 的答案

于 2013-04-12T11:13:37.737 回答