Search code examples
jsf-2richfaces

a4j:ajax valueChange event not fires


I have tried this example: Richfaces example, the valueChange event only fires if I add a submit button and click it.

I assum one of my configuration is false, as the ajax request not working.

SelectBean class:

import java.util.ArrayList;

import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;

@ManagedBean(name = "selectsBean")
@RequestScoped
public class SelectsBean
{
    private static final String[] FRUITS = { "", "Banana", "Cranberry", "Blueberry", "Orange" };
    private static final String[] VEGETABLES = { "", "Potatoes", "Broccoli", "Garlic", "Carrot" };
    private String currentItem = "";
    private String currentType = "";
    private List<SelectItem> firstList = new ArrayList<SelectItem>();
    private List<SelectItem> secondList = new ArrayList<SelectItem>();

public SelectsBean()
{
    SelectItem item = new SelectItem("", "");

    firstList.add(item);
    item = new SelectItem("fruits", "Fruits");
    firstList.add(item);
    item = new SelectItem("vegetables", "Vegetables");
    firstList.add(item);

    for (int i = 0; i < FRUITS.length; i++)
    {
        item = new SelectItem(FRUITS[i]);
    }
}

public List<SelectItem> getFirstList()
{
    return firstList;
}

public List<SelectItem> getSecondList()
{
    return secondList;
}

public static String[] getFRUITS()
{
    return FRUITS;
}

public static String[] getVEGETABLES()
{
    return VEGETABLES;
}

public void valueChanged(ValueChangeEvent event)
{
    secondList.clear();
    if (null != event.getNewValue())
    {
        String[] currentItems;

        if (((String) event.getNewValue()).equals("fruits"))
        {
            currentItems = FRUITS;
        }
        else
        {
            currentItems = VEGETABLES;
        }

        for (int i = 0; i < currentItems.length; i++)
        {
            SelectItem item = new SelectItem(currentItems[i]);

            secondList.add(item);
        }
    }
}

public String getCurrentType()
{
    return currentType;
}

public void setCurrentType(String currentType)
{
    this.currentType = currentType;
}

public String getCurrentItem()
{
    return currentItem;
}

public void setCurrentItem(String currentItem)
{
    this.currentItem = currentItem;
}

/**
 * @param args
 */
public static void main(String[] args)
{
    String webappDirLocation = "WebContent/";

    // The port that we should run on can be set into an environment variable
    // Look for that variable and default to 8080 if it isn't there.
    String webPort = System.getenv("PORT");
    if (webPort == null || webPort.isEmpty())
    {
        webPort = "8080";
    }

    Server server = new Server(Integer.valueOf(webPort));
    WebAppContext root = new WebAppContext();

    root.setContextPath("/");
    root.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
    root.setResourceBase(webappDirLocation);

    // Parent loader priority is a class loader setting that Jetty accepts.
    // By default Jetty will behave like most web containers in that it will
    // allow your application to replace non-server libraries that are part of the
    // container. Setting parent loader priority to true changes this behavior.
    // Read more here: http://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading
    root.setParentLoaderPriority(true);

    server.setHandler(root);

    try
    {
        server.start();
        server.join();
    }
    catch (Exception e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

index.xhtml:

<!DOCTYPE html 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:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:a4j="http://richfaces.org/a4j"
        xmlns:rich="http://richfaces.org/rich">
        <h:form>
            <h:selectOneMenu value="#{selectsBean.currentType}" valueChangeListener="#{selectsBean.valueChanged}">
                <f:selectItems value="#{selectsBean.firstList}" />
                <a4j:ajax event="valueChange" render="second" execute="@this" />
            </h:selectOneMenu>
            <a4j:outputPanel id="second" layout="block">
                <h:selectOneMenu value="#{selectsBean.currentType}" rendered="#{not empty selectsBean.currentType}">
                    <f:selectItems value="#{selectsBean.secondList}" />
                </h:selectOneMenu>
            </a4j:outputPanel>
        </h:form>
    </ui:composition>

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>JSFExamples</groupId>
  <artifactId>JSFExamples</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

    <properties>
        <java.version>1.7</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>

        <!-- Jetty -->
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>7.6.0.v20120127</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-webapp</artifactId>
            <version>7.6.0.v20120127</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jsp-2.1-glassfish</artifactId>
            <version>2.1.v20100127</version>
        </dependency>

        <!-- Servlet Faces API -->
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.7</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.7</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.primefaces.extensions</groupId>
            <artifactId>all-themes</artifactId>
            <version>1.0.8</version>
        </dependency>


        <!-- RichFaces libraries -->

        <dependency>
            <groupId>org.richfaces.ui</groupId>
            <artifactId>richfaces-components-ui</artifactId>
            <version>4.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.core</groupId>
            <artifactId>richfaces-core-impl</artifactId>
            <version>4.1.0.Final</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <webXml>WebContent\WEB-INF\web.xml</webXml>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>JSFExamples</display-name>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <context-param>
        <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>resources.application</param-value>
    </context-param>
    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>
</web-app>

faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">
    <managed-bean>
        <managed-bean-name>selectsBean</managed-bean-name>
        <managed-bean-class>SelectsBean</managed-bean-class>
        <managed-bean-scope>none</managed-bean-scope>
    </managed-bean>

</faces-config>

Solution

  • Your XHTML produces broken HTML output.

    You forgot the <html><h:head><h:body> in XHTML.

    Particularly the <h:head> part is mandatory for JSF in order to auto-include JavaScript and CSS files associated with some components, such as <a4j:ajax>.

    Fix it accordingly. The index.xhtml should look like this:

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:a4j="http://richfaces.org/a4j"
        xmlns:rich="http://richfaces.org/rich"
    >
        <h:head>
            <title>Put your title here.</title>
        </h:head>
        <h:body>
            <h:form>
                Put your original form here.
            </h:form>
        </h:body>
    </html>
    

    See also:


    Unrelated to the concrete problem, that JSF 1.x way of of <managed-bean> declaration in faces-config.xml is totally unnecessary given that you already have declared it via JSF 2.x flavored @ManagedBean annotation. Make sure that you focus on JSF 2.x targeted resources while learning and seeking for answers, not on JSF 1.x targeted ones, else it will only confuse you.