1

I have a form with 2 radio buttons: "type1" and "type2". If "type1" is chosen, then a dropdown must be displayed. If "type2" is chosen, then a textfield must be displayed.

Here's the view and the controller:

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

}

When I start my application, I have the following in my stdout:

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

However, nothing happens in the UI when I choose another type. How is this caused and how can I solve it?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
tweetysat
  • 2,187
  • 14
  • 38
  • 75

2 Answers2

4

JSF generates HTML. JS/Ajax works on HTML. JS/Ajax updates HTML elements by finding it in HTML DOM tree by document.getElementById() and replacing its contents based on Ajax response. However, if a JSF component is instructed to not render HTML, then JS/Ajax cannot find it in the HTML DOM tree and thus can't replace anything.

You can only ajax-update the HTML representation of a JSF component which is always rendered. So, wrap them in e.g. a <h:panelGroup>.

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

See also:


Unrelated to the concrete problem, that getIsType1() method is clumsy. Just do the comparison directly in the view so that you can get rid of it.

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

or perhaps, more matching your initial question,

<h:selectOneMenu ... rendered="#{testBean.type == 'type1'}" />
<h:inputText ... rendered="#{testBean.type == 'type2'}" />
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Ok, thanks BalusC. I tried what you explained but it's still not working. I also changed according to your unrelated remark. I add a sysout on the setter and getter of 'type'. So I have 6 times 'getType : type1' when I start the application (why 6 times ?) but nothing else more when I select another type. – tweetysat Apr 12 '13 at 06:23
  • Is an ajax request been sent or not? Debug the HTTP traffic. As to 6 times being called, see http://stackoverflow.com/questions/4281261/why-is-the-getter-called-so-many-times-by-the-rendered-attribute/4281608#4281608 This shouldn't harm if you aren't doing any business logic in there. – BalusC Apr 12 '13 at 10:46
4

Try to replace xhtml code with the following code

<!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>

Main problem in your code is,

  1. Missing h:head to import jsf.js which is required for jsf ajax.
  2. Please wrap your component into a panelGroup as suggested by @BaluC because once the component not rendered (not available on page) then the ajax on it will not work with its id.

And regarding number of time getIsType1() method calling is due to the rendered attribute, for more information check @Baluc's answer here

Community
  • 1
  • 1
Jitesh
  • 1,384
  • 10
  • 20