h:selectOneMenu中的f:ajax监听器方法未被执行

15

页面使用托管bean生成正确的值,但这两个h:selectOneMenu中的ajax事件不起作用。监听器未被调用。错误可能在标签内部,但我没有看到它。

<f:view>
    <h:form>
        <h:messages />
        <h:panelGrid columns="3">

            <h:outputLabel value="Choose your faculty: *" for="faculties" />
            <h:selectOneMenu id="faculties" value="#{registrateStudent.selectedFaculty}" >
                <f:ajax event="change" listener="#{registrateStudent.genSpecializations}" execute="faculties" render="specializations" />                        
                <f:selectItems value="#{registrateStudent.listFaculty}" var="curFac" itemLabel="#{curFac.name}" itemValue="#{curFac}" />
            </h:selectOneMenu>
            <h:message id="message_faculties" for="faculties" />

            <h:outputLabel value="Choose your specialization: *" for="specializations" />
            <h:selectOneMenu id="specializations" value="#{registrateStudent.selectedSpecialization}" >
                <f:selectItems value="#{registrateStudent.listSpecialization}" var="curSpec" itemLabel="#{curSpec.name}" itemValue="#{curSpec}"/>
            </h:selectOneMenu>
            <h:message id="message_specializations" for="specializations" />                    

托管 Bean:

@ManagedBean(name = "registrateStudent")
@ViewScoped
public class RegistrateStudent {


    private Faculty selectedFaculty;
    private List<Faculty> listFaculty;
    private Specialization selectedSpecialization;
    private List<Specialization> listSpecialization;
    private boolean showSpecialization = false;


    /** Creates a new instance of RegistrateStudent */
    public RegistrateStudent() {
        users = new Users();
        System.out.println("poaposd1");
        student = new Student();
    }

    @PostConstruct
    public void init() {
        listFaculty = ff.findAll();
        if (listFaculty != null) {
            selectedFaculty = listFaculty.get(0);
            listSpecialization = sf.findByFaculty(selectedFaculty.getIdFaculty());
            if (listSpecialization != null) {
                selectedSpecialization = listSpecialization.get(0);
            }
            else {}
        } else {}
    }

   public void genSpecializations(AjaxBehaviorEvent event) {
        if (sf.findByFaculty(selectedFaculty.getIdFaculty()) != null) {
            this.showSpecialization = true;
        } else {
            JsfUtil.addSuccessMessage("faculties", "We don't have specializations for such faculty");
        }
    }
}

更新:

我发现了一些有趣的事情:

<f:ajax> 标签在 <h:link><h:selectOneMenu><h:button><h:commandButton> 中不起作用。在这种情况下,render 属性中的错误值不会被注意到,但是 event 属性中的错误值会生成错误。

<h:outputLabel><h:inputText><f:ajax> 正常工作。


你尝试过使用 execute="@this" 而不是 execute="faculties" 吗? - George Suaridze
2个回答

36
< p > <f:ajax> 需要在HTML的<head>中包含jsf.js文件,该文件包含所有用于执行JSF ajax操作的JS函数。

为了实现这一点,请确保您使用的是主模板中的<h:head>而不是<head>。然后,JSF将自动在那里包含必要的<script>元素,指向jsf.js

<!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">
    <h:head>
        <title>Look, with h:head</title>
    </h:head>
    <h:body>
        Put your content here.
    </h:body>
</html>

请注意,在像Firefox的Web Developer Toolbar和/或Firebug这样具有不错的Web开发工具集的网页浏览器中,当执行ajax请求时,您应立即注意到JS错误,例如jsf未定义。这至少应该让您思考一些问题。

更新:根据您的更新,我发现了一些有趣的事情:

<f:ajax>标签不能在<h:link><h:selectOneMenu><h:button><h:commandButton>中使用。在这种情况下,render属性中的不正确的值不会被注意到,但是event属性的不正确值会生成错误。

<h:outputLabel><h:inputText><f:ajax>正常工作。

<h:link><h:button>仅用于GET请求,而不是POST请求。但是,在<h:selectOneMenu><h:commandButton>上应该可以正常工作。您是否在问题简化时省略了更多代码?您正在使用哪个JSF实现/版本?您是否在类路径中使用正确的库?看起来您一定搞砸了什么。

为了说服您(和我自己),我刚刚创建了以下复制粘贴并可运行的测试案例。

<!DOCTYPE html>
<html lang="en"
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
>
    <h:head>
        <title>SO question 6089924</title>
    </h:head>
    <h:body>
        <h:form>
            <h:selectOneMenu value="#{bean.selected}">
                <f:selectItem itemValue="#{null}" itemLabel="Select..." />
                <f:selectItem itemValue="one" />
                <f:selectItem itemValue="two" />
                <f:selectItem itemValue="three" />
                <f:ajax listener="#{bean.listener}" render="result" />
            </h:selectOneMenu>
        
            <h:commandButton value="commandButton" action="#{bean.submit}">
                <f:ajax listener="#{bean.listener}" render="result" />
            </h:commandButton>
        
            <h:outputText id="result" value="#{bean.selected} #{bean.result}" />
            
            <h:messages />
        </h:form>
    </h:body>
</html>

与此Bean相关
package com.example;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.AjaxBehaviorEvent;

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private String selected;
    private String result;

    public void submit() {
        System.out.println("submit");
    }
    
    public void listener(AjaxBehaviorEvent event) {
        System.out.println("listener");
        result = "called by " + event.getComponent().getClass().getName();
    }

    public String getSelected() {
        return selected;
    }

    public void setSelected(String selected) {
        this.selected = selected;
    }

    public String getResult() {
        return result;
    }

}

它在Tomcat 7.0.12上和Mojarra 2.1.1一起运行良好。

INFO: Starting Servlet Engine: Apache Tomcat/7.0.12
INFO: Initializing Mojarra 2.1.1 (FCS 20110408) for context '/playground'

谢谢您的示例。我猜想当我将<h:form>标签移动到<h:selectOneMenu>下面时,由于POST请求,value="#{bean.selected}"没有映射到bean的属性?另外,为什么即使元素不在这个<h:form>中,h:outputLabel没有h:form也无法工作? - kolobok
HTML输入元素,如<input><select><textarea>需要放在HTML <form>中,以便将值发送到服务器。JSF也是同样的情况(因为它基本上只是生成一堆HTML)。在您最初的问题代码片段中,您做得很对。所有代表HTML输入元素的JSF组件已经在一个表单中了。<h:outputLabel>只是呈现一个没有语义表单输入值的HTML <label>元素。但是,您可以将onclick操作绑定到它上面。 - BalusC
@BalusC 我注意到当使用 #{null} 时,"#{bean.listener}" 根本不会被执行,我们该如何解释这个问题?用 #{null} 表示空选择是最佳实践吗? - ziMtyth
@BalusC 当我使用itemValue=0时,该方法被调用,当我将itemValue设置为 #{null} 时,该方法不会被执行(我在控制台上进行了测试)。我认为这与您发布的链接无关。 - ziMtyth

0

如果您使用了f:metadataf:viewparam标签,请注意参数的setter方法将在每个ajax请求时被调用。

如果在调用ajax请求时出现任何错误/异常,您能提供错误日志吗?


1
没有任何错误或异常。我刚刚注意到,当我更改第一个h:selectOneMenu时,另一个被重新渲染,正如它应该的那样,但是监听器仍然没有被调用。 - kolobok
2
你能否在方法的开头加上System.out.println来确保它真的没有被调用吗? - aseychell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接