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

问题描述 投票:326回答:10

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

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

jsf jsf-2 action commandbutton commandlink
10个回答
656
投票

介绍

每当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开发人员工具集,然后打开控制台选项卡),然后查看下面可能的原因列表。

可能的原因

  1. 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
  2. 您不能将多个UIForm组件嵌套在一起。这在HTML中是非法的。浏览器行为未指定。注意包含文件!您可以并行使用UIForm组件,但在提交期间它们不会互相处理。你也应该注意“神形”反模式;确保您不会无意中以相同的形式处理/验证所有其他(不可见)输入(例如,以相同的形式具有所需输入的隐藏对话框)。另见How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?
  3. 不应该发生UIInput值验证/转换错误。您可以使用<h:messages>显示任何特定于输入的<h:message>组件未显示的消息。不要忘记在id中加入<h:messages><f:ajax render>(如果有的话),这样它也会在ajax请求中更新。另见h:messages does not display messages when p:commandButton is pressed
  4. 如果UICommandUIInput组件放在<h:dataTable><ui:repeat>等迭代组件中,那么您需要确保在表单提交请求的应用请求值阶段保留了与迭代组件完全相同的value。 JSF将重申它以查找单击的链接/按钮和提交的输入值。将bean放在视图范围中和/或确保在bean的@PostConstruct中加载数据模型(因此不在getter方法中!)应该修复它。另见How and when should I load the model from database for h:dataTable
  5. 如果动态源(如UICommand)包含UIInput<ui:include src="#{bean.include}">组件,则需要确保在表单提交请求的视图构建时间内保留完全相同的#{bean.include}值。 JSF将在构建组件树期间重新执行它。将bean放在视图范围中和/或确保在bean的@PostConstruct中加载数据模型(因此不在getter方法中!)应该修复它。另见How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
  6. 组件及其所有父项的rendered属性以及任何父test / <c:if><c:when>属性在表单提交请求的应用请求值阶段不应评估为false。 JSF将重新检查它作为防范篡改/黑客攻击请求的一部分。在@ViewScoped bean中存储负责该条件的变量,或者确保在@PostConstruct bean的@RequestScoped中正确预先初始化该条件应该修复它。这同样适用于组件的disabled属性,在应用请求值阶段不应评估为true。另见JSF CommandButton action not invokedForm submit in conditionally rendered component is not processed
  7. onclick组件的UICommand属性和onsubmit组件的UIForm属性不应返回false或导致JavaScript错误。在<h:commandLink><f:ajax>的情况下,在浏览器的JS控制台中也不会出现JS错误。通常谷歌搜索确切的错误信息已经给你答案。另见Adding jQuery to PrimeFaces results in Uncaught TypeError over all place
  8. 如果您通过JSF 2.x <f:ajax>使用Ajax或者例如PrimeFaces <p:commandXxx>,确保你在主模板中有一个<h:head>而不是<head>。否则,JSF将无法自动包含包含Ajax函数的必要JavaScript文件。这将导致JavaScript错误,例如“mojarra未定义”或浏览器的JS控制台中未定义“PrimeFaces”。另见h:commandLink actionlistener is not invoked when used with f:ajax and ui:repeat
  9. 如果您正在使用Ajax,请确保UIInput涵盖的UICommand<f:ajax execute>组件或<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
  10. 如果具有<h:form>按钮的UICommand的父级预先由来自同一页面中的另一个表单的ajax请求呈现/更新,则第一个操作将始终失败。第二个及后续操作将起作用。这是由视图状态处理中的错误引起的,该错误报告为JSF spec issue 790并且当前计划在JSF 2.3中修复。对于较旧的JSF版本,您需要在<h:form>render中明确指定<f:ajax>的ID。另见h:commandButton/h:commandLink does not work on first click, works only on second click
  11. 如果<h:form>设置了enctype="multipart/form-data"以支持文件上载,那么您需要确保至少使用JSF 2.2,或者正确配置负责解析multipart / form-data请求的servlet过滤器,否则FacesServlet最终将不会获得任何请求参数,因此无法应用请求值。如何配置此类过滤器取决于正在使用的文件上载组件。对于Tomahawk <t:inputFileUpload>,检查this answer和PrimeFaces <p:fileUpload>,检查this answer。或者,如果您实际上根本没有上传文件,则完全删除该属性。
  12. 确保ActionEventactionListener参数是javax.faces.event.ActionEvent,因此不是java.awt.event.ActionEvent,这是大多数IDE建议的第一个自动完成选项。如果你使用actionListener="#{bean.method}",没有争论也是错误的。如果您不想在方法中使用参数,请使用actionListener="#{bean.method()}"。或许你真的想用action而不是actionListener。另见Differences between action and actionListener
  13. 确保请求 - 响应链中没有PhaseListener或任何EventListener已更改JSF生命周期以跳过调用操作阶段,例如调用FacesContext#renderResponse()FacesContext#responseComplete()
  14. 确保同一请求 - 响应链中没有FilterServlet以某种方式阻止了对FacesServlet的请求。
  15. 框架中的错误。例如,当使用带有conversion error属性的rich:calendar UI元素(或者在某些情况下,使用defaultLabel子元素)时,RichFaces有一个“rich:placeholder”。如果没有为日历日期设置任何值,则此错误会阻止调用bean方法。跟踪框架错误可以通过从一个简单的工作示例开始并重新构建页面直到发现错误来完成。
  16. 如果你使用PrimeFaces <p:dialog><p:overlayPanel>,那么请确保他们有自己的<h:form>。因为,这些组件默认由JavaScript重定位到HTML <body>的末尾。因此,如果他们最初坐在<form>内,那么他们现在不会再坐在<form>。另见p:commandbutton action doesn't work inside p:dialog

调试提示

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

js console

单击“网络”选项卡以查看HTTP流量监视器。提交表单并调查请求标题和表单数据以及响应正文是否符合预期。下面的屏幕截图是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


-1
投票

我修正了我的问题:

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

52
投票

如果你的h:commandLinkh:dataTable里面,那么h:commandLink可能不起作用的另一个原因是:

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

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


26
投票

虽然我的答案不是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",因为这是用于执行自定义javascript而不会向服务器发出ajax / non-ajax请求的Push按钮。

为此,您可以分配type属性(默认值为"submit")或者您可以明确使用type="submit"

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


3
投票

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


3
投票

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

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

我有一个下拉组件,用于选择要显示的行数。支持这一领域的价值在RequestScope。支持表本身的数据是在某种ViewScope(实际上,暂时在SessionScope)。

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

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

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


2
投票

我也有这个问题,并且在打开浏览器的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
投票

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.