未调用commandButton / commandLink / ajax动作/侦听器方法或未设置/更新input值
有时,在使用<h:commandLink>
, <h:commandButton>
或<f:ajax>
,与标签关联的action
, actionListener
或listener
方法不会被调用。 或者,bean属性不会使用提交的UIInput
值进行更新。
这有什么可能的原因和解决办法?
介绍
只要UICommand
组件( <h:commandXxx>
, <p:commandXxx>
等)无法调用关联的操作方法,或者UIInput
组件( <h:inputXxx>
, <p:inputXxxx>
等)无法处理提交值和/或更新模型值,并且在服务器日志中没有看到任何可search的exception和/或警告,也不是在按照JSF ajax请求中的exception处理configurationajaxexception处理程序时,也不是在设置在web.xml
中的上下文参数下面,
<context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param>
而且您在浏览器的JavaScript控制台中也没有看到任何可search的错误和/或警告(按下Chrome / Firefox23 + / IE9 +中的F12打开Web开发人员工具集,然后打开“ 控制台”选项卡),然后查看可能的原因列表。
可能的原因
-
UICommand
和UIInput
组件必须放在UIForm
组件中,例如<h:form>
(因此不是纯HTML<form>
),否则不能发送到服务器。UICommand
组件还必须没有type="button"
属性,否则它将是一个UICommand
,仅对JavaScriptonclick
有用。 另请参见如何发送表单input值并在JSF bean中调用方法,并且<h:commandButton>不会启动回发 。 -
您不能将多个
UIForm
组件相互嵌套。 这在HTML中是非法的。 浏览器的行为是未指定的。 注意包含文件! 您可以并行使用UIForm
组件,但在提交期间不会相互处理。 你还应该注意“神形”反模式; 确保你不会无意中以相同的forms处理/validation所有其他(不可见的)input(例如,以相同的forms具有所需input的隐藏对话框)。 另请参见如何在JSF页面中使用<h:form>? 单一forms? 多种forms? 嵌套表单? 。 -
应该没有发生
UIInput
值validation/转换错误。 您可以使用<h:messages>
显示任何特定于input的<h:message>
组件未显示的<h:message>
。 不要忘记在<f:ajax render>
包含<h:messages>
的id
(如果有的话),以便在ajax请求中更新。 另请参阅h:按下p:commandButton时,消息不显示消息 。 -
如果将
UICommand
或UIInput
组件放置在迭代组件(如<h:dataTable>
,<ui:repeat>
等)中,则需要确保在应用请求值阶段保留了完全相同的迭代组件值表单提交请求。 JSF会重申一遍,find点击链接/button并提交input值。 将bean放在视图范围中,并确保在bean的@PostConstruct
中加载数据模型(因此不在getter方法中)应该修复它。 另请参见如何以及何时从h:dataTable的数据库加载模型 。 -
在表单提交请求的应用请求值阶段,组件的
rendered
属性及其所有父项和任何父<c:if>
/<c:when>
的test
属性不应评估为false
。 JSF将重新检查它作为防范篡改/被黑客请求的一部分。 将负责该条件的variables存储在@ViewScoped
bean中,或者确保您正确@ViewScoped
初始化@RequestScoped
bean的@PostConstruct
中的条件应该可以解决这个问题。 这同样适用于组件的disabled
属性,在应用请求值阶段,该属性不应评估为true
。 另请参阅未调用JSF CommandButton操作,并且不处理有条件呈现组件中的表单提交 。 -
UICommand
组件的onclick
属性和UICommand
组件的onsubmit
属性不应返回false
或导致JavaScript错误。 在<h:commandLink>
或者<f:ajax>
情况下,在浏览器的JS控制台中也不会出现JS错误。 通常用Googlesearch确切的错误信息已经给你答案。 另请参见向PrimeFaces添加jQuery将导致Uncaught TypeError覆盖整个地方 。 -
如果您通过JSF 2.x
<f:ajax>
或例如PrimeFaces<p:commandXxx>
使用Ajax,请确保在主模板而不是<head>
具有<h:head>
<head>
。 否则,JSF将无法自动包含包含Ajax函数的必要JavaScript文件。 这将导致在浏览器的JS控制台中出现像“mojarra未定义”或“PrimeFaces未定义”的JavaScript错误。 另请参阅h:与f:ajax和ui:repeat一起使用时,不会调用commandLink actionlistener 。 -
如果您正在使用Ajax,请确保感兴趣的
UIInput
和UICommand
组件被<f:ajax execute>
或<p:commandXxx process>
覆盖,否则将不会被执行/处理。 另请参见在将<f:ajax>添加到<h:commandButton>并了解PrimeFaces过程/更新和JSF f:ajax execute / render属性 时,在模型中未提交表单值 。 -
如果具有
UICommand
button的<h:form>
的UICommand
事先由来自同一页中另一个表单的ajax请求呈现/更新,则第一个操作将始终失败。 第二次和以后的行动将起作用。 这是由视图状态处理中的一个错误造成的,这个错误被报告为JSF规范问题790 ,目前计划在JSF 2.3中修复。 对于较老的JSF版本,您需要在<f:ajax>
的render
中明确指定<h:form>
的ID。 另请参阅h:commandButton / h:commandLink在第一次单击时不起作用,仅在第二次单击时才起作用 。 -
如果
<h:form>
为了支持file upload而设置了enctype="multipart/form-data"
,那么您需要确保您至less使用了JSF 2.2,或者负责的servletfilterparsingmultipart / form-data请求的configuration是正确的,否则FacesServlet
将最终没有得到任何请求参数,从而无法应用请求值。 如何configuration这样的filter取决于正在使用的file upload组件。 对于Tomahawk<t:inputFileUpload>
,检查这个答案和PrimeFaces<p:fileUpload>
,检查这个答案 。 或者,如果您实际上没有上传文件,请完全删除该属性。 -
确保
actionListener
的ActionEvent
参数是一个javax.faces.event.ActionEvent
,因此不是java.awt.event.ActionEvent
,这是大多数IDEbuild议的第一个自动完成选项。 没有参数也是错误的,如果你使用actionListener="#{bean.method}"
。 如果您不想在方法中使用参数,请使用actionListener="#{bean.method()}"
。 或者,也许你真的想要使用action
而不是actionListener
。 另请参见action和actionListener之间的区别 。 -
通过调用
FacesContext#renderResponse()
或FacesContext#responseComplete()
确保请求 – 响应链中没有PhaseListener
或任何EventListener
更改了JSF生命周期以跳过调用操作阶段。 -
确保在同一请求 – 响应链中没有
Filter
或Servlet
以某种方式阻止了对FacesServlet
的请求。 -
在框架中的错误。 例如,RichFaces在使用具有
defaultLabel
属性(或者在某些情况下为rich:placeholder
子元素)的rich:calendar
UI元素时会出现“ 转换错误 ”。 此错误防止未设置datedate值时调用bean方法。 跟踪框架错误可以通过从一个简单的工作示例开始,并build立该页面,直到发现错误。
debugging提示
如果你仍然困惑,是时候去debugging了。 在客户端,按Web浏览器中的F12打开Web开发人员工具集。 点击Console选项卡,查看JavaScript的conosle。 它应该没有任何JavaScript错误。 下面的屏幕截图是一个来自Chrome的示例,它演示了在未声明<h:head>
的情况下提交<f:ajax>
button(如上面第7点所述)的情况。
单击networking选项卡查看HTTP通信量监视器。 提交表单并调查请求标题和表单数据以及响应主体是否符合预期。 下面的截图是Chrome的一个例子,它演示了一个简单的表单成功的用一个<h:inputText>
和一个<h:commandButton>
与<f:ajax execute="@form" render="@form">
。
(警告:当您从生产环境中从HTTP请求标头上传截图时,请确保您在截图中对任何会话cookie进行了加扰/混淆处理,以避免会话劫持攻击!)
在服务器端,确保服务器以debugging模式启动。 将一个debugging断点放入您期望在处理表单提交期间调用的感兴趣的JSF组件的方法中。 例如在UICommand
组件的情况下,这将是UICommand#queueEvent()
和UIInput
组件的情况下,这将是UIInput#validate()
。 只需执行代码执行,并检查stream程和variables是否符合预期。 下面的截图是Eclipsedebugging器的一个例子。
如果你的h:commandLink
在h:dataTable
,h:commandLink可能不起作用的另一个原因是:
绑定到h:dataTable
的底层数据源也必须在单击链接时触发的第二个JSF生命周期中可用。
所以如果底层的数据源是请求作用域的话,那么h:commandLink
不起作用!
虽然我的答案并不是100%适用,但大多数search引擎认为这是第一次打击,我决定发布它毫无意义:
如果你正在使用PrimeFaces (或者一些类似的API) p:commandButton
或者p:commandLink
,你可能忘记了在你的命令组件中显式添加process="@this"
。
正如PrimeFaces用户指南在3.18节所述, process
和update
的默认值都是@form
,这几乎与您对普通JSF f:ajax
或RichFaces所预期的默认值@form
f:ajax
execute="@this"
和render="@none"
分别。
我花了一个时间找出来。 (…而且我认为使用与JSF不同的默认是相当不明确的!)
我会提到一个关于Primefaces的p:commandButton
!
当你使用p:commandButton
作为需要在服务器上完成的动作的时候,你不能使用type="button"
因为这是用于执行自定义javascript的button ,而不会导致ajax / non-ajax请求到服务器。
为此,您可以分配type
属性(默认值为"submit"
),或者您可以显式使用type="submit"
。
希望这会帮助别人!
我最近碰到一个UICommand的问题,在使用IBM Extended Faces组件的JSF 1.2应用程序中没有调用。
我有一个数据表的行(扩展版本,所以<hx:datatable>
)的命令button和UICommand不会触发表中的某些行(不会触发的行是大于默认行显示大小)。
我有一个下拉组件select要显示的行数。 支持此字段的值在RequestScope
。 支持表本身的数据是一种ViewScope
(实际上,暂时在SessionScope
)。
如果通过控件增加了行显示,而该值也绑定到了数据表的rows
属性,则由于此更改而显示的行不会在单击时触发UICommand。
将该属性放置在与表数据本身相同的范围内解决了问题。
我认为这是在上面的BalusC#4中提到的,不仅表值需要是View或Session作用域,还有控制要在该表上显示的行数的属性。
我也遇到了这个问题,打开浏览器的Web控制台之后,才真正开始了解根本原因。 在此之前,我无法得到任何错误消息(即使使用<p:messages>
)。 Web控制台显示从<h:commandButton type="submit" action="#{myBean.submit}">
返回的HTTP 405状态码。
在我的情况下,我有一个混合香草HttpServlet提供OAuthauthentication通过Auth0和JSF facelets和豆执行我的应用程序视图和业务逻辑。
一旦我重构了我的web.xml,并删除了一个中间人servlet,然后“神奇”的工作。
底线是,问题在于中间人servlet使用RequestDispatcher.forward(…)将HttpServlet环境redirect到JSF环境,而之前调用的servlet使用HttpServletResponse.sendRedirectredirect(.. )。
基本上,使用sendRedirect()允许JSF“容器”来控制,而RequestDispatcher.forward()显然不是。
我不知道的是为什么Facelet能够访问bean的属性,但无法设置它们,这显然是为了取消servlet和JSF的混合而尖叫,但是我希望这能帮助某人避免几个小时的头脑风暴,到餐桌拆裂。
自己陷入了这个问题,并find了这个问题的另一个原因。 如果在你的* .xhtml中使用的属性的后台bean中没有setter方法,那么这个操作就不会被调用。
我有很多的乐趣debugging一个问题,其中在richfaces
中的<h:commandLink>
操作拒绝触发。 这张桌子在某个时间点工作,但没有明显的原因停下来。 我不遗余力地发现,只有发现我的rich:datatable
使用了错误的rowKeyConverter
,它返回的值为richfaces愉快地用作行键的值。 这阻止了我的<h:commandLink>
动作被调用。
还有一种可能性:如果症状是第一次调用起作用,但后来的调用不起作用,则可以使用JSF 2.2中的PrimeFaces 3.x,如下所述: 不发送ViewState 。