h:selectOneMenu 中的 f:ajax 监听方法没有执行

Posted

技术标签:

【中文标题】h:selectOneMenu 中的 f:ajax 监听方法没有执行【英文标题】:The f:ajax listener method in h:selectOneMenu is not executed 【发布时间】:2011-08-30 16:50:20 【问题描述】:

在托管 bean 中使用适当的值正确生成了页面,但是这两个 h:selectOneMenus 中的 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");
        
    

更新:

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

&lt;f:ajax&gt; 标签在 &lt;h:link&gt;&lt;h:selectOneMenu&gt;&lt;h:button&gt;&lt;h:commandButton&gt; 上不起作用。在这种情况下,render 属性中的错误值不会被注意到,但event 属性中的错误值会产生错误。

&lt;h:outputLabel&gt;, &lt;h:inputText&gt;&lt;f:ajax&gt; 正确配合

【问题讨论】:

你试过用 execute="@this" 代替 execute="faculties" 吗? 【参考方案1】:

&lt;f:ajax&gt; 要求将 jsf.js 文件包含在 html &lt;head&gt; 中。它包含用于执行 JSF ajax 魔术的所有 JS 函数。

要实现这一点,请确保您在主模板中使用 &lt;h:head&gt; 而不是 &lt;head&gt;。 JSF 会自动在其中包含必要的&lt;script&gt; 元素,指向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 请求时,您应该立即注意到像 jsf is undefined 这样的 JS 错误。这至少应该引起一些思考。


更新:根据您的更新

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

&lt;f:ajax&gt; 标签在 &lt;h:link&gt;&lt;h:selectOneMenu&gt;&lt;h:button&gt;&lt;h:commandButton&gt; 上不起作用。在这种情况下,render 属性中的错误值不会被注意到,但event 属性中的错误值会产生错误。

&lt;h:outputLabel&gt;&lt;h:inputText&gt;&lt;f:ajax&gt; 正确配合。

&lt;h:link&gt;&lt;h:button&gt; 仅用于 GET 请求,而不用于 POST 请求。但是,它应该可以在 &lt;h:selectOneMenu&gt;&lt;h:commandButton&gt; 上正常工作。为了简单起见,您在问题中省略的完整图片中没有更多代码吗?您使用的是哪个 JSF impl/version?您是否在类路径中使用了正确的库?看来你一定是真的搞砸了。

为了说服你(和我自己),我刚刚创建了以下 copy'n'paste'n'runnable 测试用例

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

用这个豆子

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;
    


Mojarra 2.1.1 在 Tomcat 7.0.12 上运行良好。

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

【讨论】:

例如,谢谢。我想value="#bean.selected" 没有映射到 bean 的属性,当我因为 POST 请求而将 &lt;h:form&gt; 标签移动到 &lt;h:selectOneMenu&gt; 下时?以及为什么即使元素不在此 h:form 中, h:outputLabel 也无法在没有 h:form 的情况下工作? HTML 输入元素,如&lt;input&gt;&lt;select&gt;&lt;textarea&gt; 需要进入 HTML &lt;form&gt; 以获取发送到服务器的值。同样的故事也适用于 JSF(因为它基本上所做的只是生成一堆 HTML)。在您的原始问题代码 sn-p 中,您做对了。所有代表 HTML 输入元素的 JSF 组件都已经在一个表单中。 &lt;h:outputLabel&gt; 只是呈现一个没有语义表单输入值的 HTML &lt;label&gt; 元素。但是,您可以将 onclick 操作绑定到它。 @BalusC 我注意到在使用#null 时,“#bean.listener”根本没有被执行,我们该如何解释呢?用#null 表示空选择是否是最佳做法? @BalusC 当我使用itemValue=0 时调用该方法,当我将itemValue 设置为#null 时该方法未执行(我在控制台上进行了打印测试)。我认为它与您发布的链接无关。【参考方案2】:

如果您有f:metadataf:viewparam 标签,请小心,因为每个ajax 请求都会调用参数的设置器。

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

【讨论】:

没有任何错误或异常。另外我刚刚注意到,当我更改第一个 h:selectOneMenu 时,另一个被重新渲染,这是应该的,但仍然没有调用监听器。 你能把 System.out.println 放在方法的开头,以确保它真的没有被调用吗?

以上是关于h:selectOneMenu 中的 f:ajax 监听方法没有执行的主要内容,如果未能解决你的问题,请参考以下文章

JSF2 <h:selectOneMenu 和 <f:ajax 侦听器在 PrettyFaces 过滤器导航之后未调用

何时使用 valueChangeListener 或 f:ajax 监听器?

如何让 h:inputText 的必需属性依赖于 h:selectOneMenu 中的某些值集?

基于 h:selectOneMenu 值渲染 [重复]

<h:selectOneMenu> 为所有下拉列表调用值更改侦听器,而不仅仅是当前

如何使用自定义 JSF 转换器将 h:selectOneMenu 项转换为 List<String>?