【问题标题】:Conditionally render h:selectOneMenu and h:inputText by ajax depending on h:selectOneRadio selection根据 h:selectOneRadio 选择,通过 ajax 有条件地渲染 h:selectOneMenu 和 h:inputText
【发布时间】:2013-04-03 18:49:52
【问题描述】:

我有一个带有 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 中没有任何反应。这是如何引起的,我该如何解决?

【问题讨论】:

    标签: ajax jsf-2


    【解决方案1】:

    尝试用下面的代码替换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 的答案here

    【讨论】:

      【解决方案2】:

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

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

      <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'}" />
      

      【讨论】:

      • 好的,谢谢 BalusC。我尝试了您的解释,但仍然无法正常工作。我也根据你无关的言论进行了更改。我在'type'的setter和getter上添加了一个sysout。因此,当我启动应用程序时,我有 6 次 'getType : type1'(为什么是 6 次?),但当我选择另一种类型时,仅此而已。
      • 是否发送了ajax请求?调试 HTTP 流量。至于 6 次被调用,请参阅 stackoverflow.com/questions/4281261/… 如果您不在那里执行任何业务逻辑,这应该不会造成伤害。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 2017-02-22
      • 2020-06-12
      相关资源
      最近更新 更多