首页 文章

commandButton / commandLink / ajax动作/侦听器方法未调用或输入值未设置/更新

提问于
浏览
324

有时,使用 <h:commandLink><h:commandButton><f:ajax> 时,与标签关联的 actionactionListenerlistener 方法根本就不会被调用 . 或者,bean属性不会使用提交的 UIInput 值进行更新 .

有什么可能的原因和解决方案?

10 回答

  • 3

    简介

    只要 UICommand 组件( <h:commandXxx><p:commandXxx> 等)无法调用关联的操作方法,或者 UIInput 组件( <h:inputXxx><p:inputXxxx> 等)无法处理提交的值和/或更新模型值,并且您没有看到服务器日志中的任何googlable异常和/或警告,当你按照Exception handling in JSF ajax requests配置ajax异常处理程序时,也不会在 web.xml 中设置下面的context参数时,

    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    

    并且您也没有在浏览器的JavaScript控制台中看到任何可搜索的错误和/或警告(按Chrome / Firefox23 / IE9中的F12打开Web开发人员工具集,然后打开控制台选项卡),然后通过以下可能原因列表进行操作 .

    可能的原因

    • UICommandUIInput 组件必须放在 UIForm 组件内,例如 <h:form> (因此不是纯HTML <form> ),否则无法将任何内容发送到服务器 . UICommand 组件也必须没有 type="button" 属性,否则它将是一个死按钮,仅对JavaScript onclick 有用 . 另见How to send form input values and invoke a method in JSF bean<h:commandButton> does not initiate a postback .

    • 您不能将多个 UIForm 组件相互嵌套 . 这在HTML中是非法的 . 浏览器行为未指定 . 注意包含文件!您可以并行使用 UIForm 组件,但是它们无意中以相同的形式处理/验证所有其他(不可见)输入(例如,以相同的形式具有所需输入的隐藏对话框) . 另见How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms? .

    • 不应发生 UIInput 值验证/转换错误 . 您可以使用 <h:messages> 显示任何特定于输入的 <h:message> 组件未显示的消息 . 不要忘记在 <f:ajax render> 中包含 <h:messages> <h:messages> ,如果有的话,以便它也会在ajax请求中更新 . 另见h:messages does not display messages when p:commandButton is pressed .

    • 如果 UICommandUIInput 组件放在迭代组件(如 <h:dataTable><ui:repeat> 等)内,则需要确保在表单提交请求的应用请求值阶段保留了完全相同的迭代组件 value . JSF将重申它以查找单击的链接/按钮和提交的输入值 . 将bean放在视图范围中和/或确保在bean的 @PostConstruct 中加载数据模型(因此不在getter方法中!)应该修复它 . 另见How and when should I load the model from database for h:dataTable .

    • 如果动态源(如 <ui:include src="#{bean.include}"> )包含 UICommandUIInput 组件,则需要确保在表单提交请求的视图构建期间保留完全相同的 #{bean.include} 值 . JSF将在构建组件树期间重新执行它 . 将bean放在视图范围中和/或确保在bean的 @PostConstruct 中加载数据模型(因此不在getter方法中!)应该修复它 . 另见How to ajax-refresh dynamic include content by navigation menu? (JSF SPA) .

    • 组件及其所有父项的 rendered 属性以及任何父项 <c:if> / <c:when>test 属性在表单提交请求的应用请求值阶段不应评估为 false . JSF将重新检查它作为防范篡改/黑客攻击请求的一部分 . 在 @ViewScoped bean中存储负责该条件的变量,或者确保在 @RequestScoped bean的 @PostConstruct 中正确预先初始化该条件应该修复它 . 这同样适用于组件的 disabled 属性,在应用请求值阶段不应评估为 true . 另见JSF CommandButton action not invokedForm submit in conditionally rendered component is not processed .

    • UICommand 组件的 onclick 属性和 UIForm 组件的 onsubmit 属性不应返回 false 或导致JavaScript错误 . 如果 <h:commandLink><f:ajax> 也应该在浏览器的JS控制台中看不到JS错误 . 通常谷歌搜索确切的错误信息已经给你答案 . 另见Adding jQuery to PrimeFaces results in Uncaught TypeError over all place .

    • 如果您通过JSF 2.x <f:ajax> 或例如使用AjaxPrimeFaces <p:commandXxx> ,确保主模板中有 <h:head> 而不是 <head> . 否则JSF赢得了_b97360_的JS控制台 . 另见h:commandLink actionlistener is not invoked when used with f:ajax and ui:repeat .

    • 如果您正在使用Ajax,请确保 <f:ajax execute> 涵盖感兴趣的 UIInputUICommand 组件 . <p:commandXxx process> ,否则将无法执行/处理 . 另见Submitted form values not updated in model when adding <f:ajax> to <h:commandButton>Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes .

    • 如果具有 UICommand 按钮的 <h:form> 的父级预先由来自同一页面中的另一个表单的ajax请求呈现/更新,则第一个操作将始终失败 . 第二个及后续操作将起作用 . 这是由视图状态处理中的错误引起的,该错误报告为JSF spec issue 790并且当前计划在JSF 2.3中修复 . 对于较旧的JSF版本,您需要在 <f:ajax>render 中明确指定 <h:form> 的ID . 另见h:commandButton/h:commandLink does not work on first click, works only on second click .

    • 如果 <h:form> 已设置 enctype="multipart/form-data" 以支持文件上载,那么您需要确保至少使用JSF 2.2,或者正确配置负责解析multipart / form-data请求的servlet过滤器,否则 FacesServlet 将最终没有得到任何请求参数,因此无法应用请求值 . 如何配置此类过滤器取决于正在使用的文件上载组件 . 对于Tomahawk <t:inputFileUpload> ,请检查this answer,对于PrimeFaces <p:fileUpload> ,请检查this answer . 或者,如果您实际上根本没有上传文件,则完全删除该属性 .

    • 确保 actionListenerActionEvent 参数是 javax.faces.event.ActionEvent ,因此不是 java.awt.event.ActionEvent ,这是大多数IDE建议的第一个自动完成选项 . 如果使用 actionListener="#{bean.method}" ,没有参数也是错误的 . 如果您不想在方法中使用参数,请使用 actionListener="#{bean.method()}" . 或者你可能真的想使用 action 而不是 actionListener . 另见Differences between action and actionListener .

    • 确保请求 - 响应链中没有 PhaseListener 或任何 EventListener 已更改JSF生命周期以跳过调用操作阶段,例如调用 FacesContext#renderResponse()FacesContext#responseComplete() .

    • 确保同一请求 - 响应链中没有 FilterServlet 以某种方式阻止了 FacesServlet 的请求 .

    • 框架中的错误 . 例如,当使用 rich:calendar UI元素和 defaultLabel 属性(或者在某些情况下, rich:placeholder 子元素)时,RichFaces有一个“conversion error” . 如果没有为日历日期设置任何值,则此错误会阻止调用bean方法 . 跟踪框架错误可以通过从一个简单的工作示例开始并重新构建页面直到发现错误来完成 .

    • 如果您使用的是PrimeFaces p:dialogp:overlayPanel ,请确保您没有遇到p:commandbutton action doesn't work inside p:dialog

    调试提示

    如果你仍然卡住,是时候调试了 . 在客户端,在webbrowser中按F12打开Web开发人员工具集 . 单击Console选项卡,以查看JavaScript conosle . 它应该没有任何JavaScript错误 . 下面的屏幕截图是Chrome的一个示例,它演示了在未声明 <h:head> 时提交 <f:ajax> 启用按钮的情况(如上面第7点所述) .

    js console

    单击“网络”选项卡以查看HTTP流量监视器 . 提交表单并调查请求 Headers 和表单数据以及响应正文是否符合预期 . 下面的屏幕截图是来自Chrome的一个示例,该示例演示了一个简单表单的成功ajax提交,其中包含单个 <h:inputText> 和单个 <h:commandButton> ,其中包含 <f:ajax execute="@form" render="@form"> .

    network monitor

    (警告:当您从 生产环境 环境中发布上述HTTP请求标头的屏幕截图时,请确保在屏幕截图中对任何会话cookie进行加扰/混淆,以避免会话劫持攻击!)

    在服务器端,确保服务器以调试模式启动 . 将调试断点放在您期望在处理表单提交期间调用的感兴趣的JSF组件的方法中 . 例如 . 在 UICommand 组件的情况下,那将是UICommand#queueEvent(),并且在 UIInput 组件的情况下,那将是UIInput#validate() . 只需逐步执行代码并检查流和变量是否符合预期 . 下面的截图是Eclipse调试器的一个例子 .

    debug server

  • 3

    如果 h:commandLinkh:dataTable 内,还有另一个原因导致 h:commandLink 可能无效:

    潜在的绑定到 h:dataTable 的数据源也必须在单击链接时触发的第二个JSF生命周期中可用 .

    因此,如果底层数据源是请求作用域,则 h:commandLink 不起作用!

  • 0

    虽然我的答案不是100%适用,但大多数搜索引擎都认为这是第一次点击,我决定发布它:

    如果您正在使用 PrimeFaces (或某些类似的API) p:commandButtonp:commandLink ,则可能忘记将 process="@this" 显式添加到命令组件中 .

    正如PrimeFaces用户指南在第3.18节中所述, processupdate 的默认值都是 @form ,这几乎与您可能期望的普通JSF f:ajax 或RichFaces(分别为 execute="@this"render="@none" )的默认值相反 .

    我花了很长时间才找到答案 . (...我认为使用与JSF不同的默认值是相当不清楚的!)

  • 9

    我想提一下有关Primefaces的 p:commandButton 的事情!

    当您使用 p:commandButton 进行需要在服务器上执行的操作时,您不能使用 type="button" ,因为这是 Push buttons ,用于执行自定义javascript而不会向服务器发出ajax / non-ajax请求 .

    为此,您可以分配 type 属性(默认值为 "submit" ),也可以显式使用 type="submit" .

    希望这会对某人有所帮助!

  • 25

    我自己也遇到了这个问题,并找到了解决这个问题的另一个原因 . 如果您的支持bean中没有用于* .xhtml中使用的属性的setter方法,则不会调用该操作 .

  • 2

    我最近遇到了一个问题,UICommand没有在使用IBM Extended Faces Components的JSF 1.2应用程序中调用 .

    我在数据表的一行(扩展版本,因此 <hx:datatable> )上有一个命令按钮,并且UICommand不会从表中的某些行触发(不会触发的行是大于默认行显示大小的行) .

    我有一个下拉组件,用于选择要显示的行数 . 支持此字段的值在 RequestScope 中 . 支持表本身的数据是 ViewScope (实际上,暂时在 SessionScope ) .

    如果行显示通过控件增加,该值也绑定到数据表的 rows 属性,则由于此更改而显示的任何行都不会在单击时触发UICommand .

    将此属性放在与表数据本身相同的范围内可以解决问题 .

    我认为在上面的BalusC#4中提到了这一点,但不仅表值需要是View或Session scoped,而且还有控制该表上显示的行数的属性 .

  • 650

    我也遇到了这个问题,并且在打开浏览器的Web控制台后才真正开始磨练根本原因 . 在此之前,我无法收到任何错误消息(即使使用 <p:messages> ) . Web控制台显示从 <h:commandButton type="submit" action="#{myBean.submit}"> 返回的HTTP 405状态代码 .

    在我的例子中,我有一个混合的vanilla HttpServlet通过Auth0和JSF facelets提供OAuth身份验证,并执行我的应用程序视图和业务逻辑 .

    一旦我重构了我的web.xml,并删除了一个中间人servlet,它就“神奇地”工作了 .

    最重要的是,问题是中间人servlet正在使用RequestDispatcher.forward(...)从HttpServlet环境重定向到JSF环境,而在它之前调用的servlet是用HttpServletResponse.sendRedirect重定向的(... ) .

    基本上,使用sendRedirect()允许JSF“容器”控制,而RequestDispatcher.forward()显然不是 .

    我不知道的是为什么facelet能够访问bean属性但无法设置它们,这显然是为了废除servlet和JSF的混合而尖叫,但我希望这有助于某人避免长时间的头 - 到餐桌拆裂 .

  • 0

    调试 richfaces datatable<h:commandLink> 的行动拒绝解雇时,我有很多乐趣 . 该表曾经在某个时刻工作,但没有明显原因停止 . 我不遗余力,只是发现我的 rich:datatable 正在使用错误的 rowKeyConverter ,它返回了richfaces愉快地用作行键的空值 . 这阻止了我的 <h:commandLink> 动作被调用 .

  • -1

    还有一种可能性:如果症状是第一次调用有效,但后续调用没有,则可能正在使用PrimeFaces 3.x使用JSF 2.2,详见此处:No ViewState is sent .

  • 51

    我修正了我的问题:

    <h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
    

    在:

    <h:form>
         <h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
    </h:form>
    

相关问题