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


345

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

有哪些可能的原因和解决方案?

Answers:


687

介绍

每当UICommand组件(<h:commandXxx><p:commandXxx>等)无法调用关联的操作方法,或者UIInput组件(<h:inputXxx><p:inputXxxx>等)无法处理提交的值和/或更新模型值,并且看不到任何可查询的异常和/或服务器日志中的警告,也不是按照JSF ajax请求中的异常处理配置ajax异常处理程序时,也不是在web.xml

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

并且您也没有在浏览器的JavaScript控制台中看到任何可谷歌搜索的错误和/或警告(按Chrome / Firefox23 + / IE9 +中的F12打开Web开发人员工具集,然后打开“ 控制台”标签),然后在下面列出可能的原因。

可能的原因

  1. UICommand并且UIInput组件必须放置在UIForm组件内部,例如<h:form>(因此不是纯HTML <form>),否则无法将任何内容发送到服务器。UICommand组件也必须没有type="button"属性,否则它将是一个失效按钮,仅对JavaScript有用onclick。另请参见如何在JSF bean中发送表单输入值和调用方法,并且<h:commandButton>不会启动回发

  2. 您不能相互嵌套多个UIForm组件。这在HTML中是非法的。浏览器行为未指定。当心包含文件!您可以UIForm并行使用组件,但是在提交期间它们不会相互处理。您还应该提防“上帝形态”反模式;确保您不会无意间以相同的形式处理/验证所有其他(不可见的)输入(例如,具有与输入相同形式的隐藏对话框的隐藏对话框)。另请参见如何在JSF页面中使用<h:form>?单一表格?多种形式?嵌套表格?

  3. 没有UIInput值验证/转换错误应该发生。您可以<h:messages>用来显示任何特定于输入的<h:message>组件未显示的消息。不要忘了包括id<h:messages><f:ajax render>,如果有的话,那么它将以及对Ajax请求被更新。另请参见当按下p:commandButton时,h:messages不显示消息

  4. 如果UICommandUIInput组件放置在诸如<h:dataTable><ui:repeat>等的迭代组件内,那么您需要确保value在表单提交请求的应用请求值阶段中保留与迭代组件完全相同的组件。JSF将在其上重申以找到单击的链接/按钮和提交的输入值。将bean放入视图范围和/或确保将数据模型加载@PostConstruct到bean中(因此不在getter方法中!)应该可以修复它。另请参见如何以及何时从数据库中为h:dataTable加载模型

  5. 如果动态源(例如)包含UICommandUIInput组件<ui:include src="#{bean.include}">,那么您需要确保#{bean.include}在表单提交请求的视图构建期间保留完全相同的值。JSF将在构建组件树期间重新执行它。将bean放入视图范围和/或确保将数据模型加载@PostConstruct到bean中(因此不在getter方法中!)应该可以修复它。另请参阅如何通过导航菜单Ajax刷新动态包含内容?(JSF SPA)

  6. rendered组件及其所有的父母和属性test任何父的属性<c:if>/ <c:when>不应计算为false在申请表格的请求值阶段提交请求。JSF将对其进行重新检查,以作为防范被篡改/被黑客入侵的保护措施的一部分。将负责该条件的变量存储在@ViewScopedBean中,或者确保您正确地预先初始化@PostConstruct@RequestScopedBean 的条件,则应对其进行修复。这同样适用于disabled组件的属性,true在应用请求值阶段不应评估该属性。另请参见未调用JSF CommandButton操作不处理有条件呈现的组件中的表单提交一旦将其包装在<h:panelGroup rendering>中,h:commandButton将不起作用

  7. onclick该属性UICommand组件和onsubmit该属性UIForm组件不应该返回false或导致JavaScript错误。应该在的情况下,<h:commandLink>或者<f:ajax>还没有在浏览器的JS控制台可见JS错误。通常,使用Google搜索确切的错误消息已经可以给您答案。另请参见使用PrimeFaces手动添加/加载jQuery会导致Uncaught TypeErrors

  8. 如果通过JSF 2.x <f:ajax>或例如PrimeFaces 使用Ajax <p:commandXxx>,请确保<h:head>在主模板中使用而不是<head>。否则,JSF将无法自动包含包含Ajax函数的必要JavaScript文件。这将导致浏览器的JS控制台出现JavaScript错误,例如“未定义mojarra”或“未定义PrimeFaces”。另请参见与f:ajax和ui:repeat一起使用时,不会调用h:commandLink actionlistener

  9. 如果您使用的是Ajax,并且提交的值最终为null,那么请确保或所关注的,UIInputUICommand组件被<f:ajax execute>或例如覆盖<p:commandXxx process>,否则它们将不会执行/处理。另请参见将<f:ajax>添加到<h:commandButton>了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性时,模型中未更新提交表单值

  10. 如果提交的值仍然是null,并且您正在使用CDI管理Bean,则请确保从正确的程序包中导入范围注释,否则CDI将默认设置为@Dependent在EL的每次评估中有效地重新创建Bean表达。另请参见@SessionScoped bean一直释放作用域并一直重新创建,字段变为空,并且JSF 2应用程序中的默认Managed Bean Scope是什么?

  11. 如果<h:form>带有该UICommand按钮的的父项事先是由来自同一页面中另一表单的ajax请求呈现/更新的,则第一个操作在JSF 2.2或更早版本中将始终失败。第二步和后续操作将起作用。这是由视图状态处理中的错误引起的,该错误报告为JSF规范问题790,当前已在JSF 2.3中修复。对于老版本的JSF,你需要明确指定的标识<h:form>render<f:ajax>。另请参见h:commandButton / h:commandLink在第一次单击时不起作用,仅在第二次单击时起作用

  12. 如果<h:form>enctype="multipart/form-data"设置为支持文件上传,则需要确保至少使用JSF 2.2,或者已正确配置了负责解析多部分/表单数据请求的servlet过滤器,否则FacesServlet将最终根本没有获得任何请求参数,因此无法应用请求值。如何配置此类过滤器取决于所使用的文件上传组件。对于“战斧” <t:inputFileUpload>,请检查此答案,对于PrimeFaces <p:fileUpload>,请检查此答案。或者,如果您实际上根本没有上传文件,请完全删除该属性。

  13. 确保ActionEventof 的参数actionListener是an javax.faces.event.ActionEvent,因此不是java.awt.event.ActionEvent,这是大多数IDE建议的第1个自动完成选项。如果使用,没有参数也是错误的actionListener="#{bean.method}"。如果您不想在方法中使用参数,请使用actionListener="#{bean.method()}"。或者,也许您实际上想使用action而不是actionListener。另请参见action和actionListener之间的区别

  14. 确保请求-响应链中的no PhaseListener或任何内容都不EventListener更改JSF生命周期,以通过调用FacesContext#renderResponse()或来跳过调用动作阶段FacesContext#responseComplete()

  15. 确保否FilterServlet同一请求-响应链中的请求以FacesServlet某种方式阻止了该请求。例如,登录/安全过滤器,例如Spring Security。特别是在ajax请求中,默认情况下最终将完全没有UI反馈。另请参阅Spring Security 4和PrimeFaces 5 AJAX请求处理

  16. 如果您使用的是PrimeFaces <p:dialog>或a <p:overlayPanel>,则请确保它们具有自己的<h:form>。因为,这些组件在默认情况下被JavaScript重定位到HTML的末尾<body>。因此,如果他们最初坐在内<form>,则现在不再坐在内<form>。另请参阅p:commandbutton动作在p:dialog中不起作用

  17. 框架中的错误。例如,当使用带有属性(或在某些情况下为子元素)的UI元素时,RichFaces会出现“ 转换错误 ” 。当没有为日历日期设置任何值时,此错误阻止Bean方法被调用。跟踪框架的错误可以通过从一个简单的工作示例开始并备份页面直到发现该错误来完成。rich:calendardefaultLabelrich:placeholder

调试提示

万一您仍然卡住,该进行调试了。在客户端,按Web浏览器中的F12打开Web开发人员工具集。单击控制台选项卡,以便查看JavaScript。它应该没有任何JavaScript错误。下面的屏幕截图是来自Chrome的示例,演示了<f:ajax>在未<h:head>声明的情况下提交已启用按钮的情况(如上文第7点所述)。

js控制台

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

网络监控器

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

在服务器端,请确保服务器以调试模式启动。将调试断点放在感兴趣的JSF组件的方法中,您希望在处理表单提交期间调用该方法。例如,在的情况下,UICommand部件,这将是UICommand#queueEvent()与在的情况下,UIInput部件,这将是UIInput#validate()。只需逐步执行代码并检查流程和变量是否符合预期即可。屏幕截图下方是Eclipse调试器的示例。

调试服务器


1
您的第二点让我思考了很长时间。我只是发现主文件中的f:view标记是造成我大多数问题的原因。可能是因为它呈现了表单,对吧?
Paulo Guedes

2
@pauloguedes我找不到任何表明f:view呈现表单的内容。我的理解是它只是一个容器。以我的经验,f:view不会渲染任何元素。
卢卡斯

@balusc关于第4点的一点澄清,如果commandLink不在dataTable本身中,那仍然重要吗?
卢卡斯

谢谢,关键是要点:将bean放入视图范围和/或确保将数据模型加载到bean的(post)构造函数中(因此不在getter方法中!)应该对其进行修复。
merveotesi 2013年

2
@Kukeltje:那会抛出EL异常(答案中的第一段已经涵盖)
BalusC 2015年

54

如果您h:commandLink在内h:dataTable,则还有其他原因h:commandLink可能导致无法使用:

绑定到的底层数据源h:dataTable也必须在单击链接时触发的第二个JSF-Lifecycle中可用。

因此,如果基础数据源是请求范围的,h:commandLink则无法使用!


2
好吧,这对我来说还不是很清楚。无论如何,我希望我的回答是有帮助的,因为至少就我而言,我没有明确地处理UICommand / UIData。“解决方案”正在将支持bean从请求范围提升到会话范围……
jbandi 2010年

1
我第二个Jens评论...将我的RequestScoped bean设置为SessionScoped改变了我的dataTable-谢谢
Zack Macomber

28

尽管我的回答并非100%适用,但是大多数搜索引擎都将其作为第一匹配,但我还是决定将其发布:

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

正如《 PrimeFaces用户指南》在3.18节中所述,process和的默认值update都是both @form,这与您可能期望普通JSF f:ajax或RichFaces 的默认值分别为execute="@this"render="@none"相对。

只是花了我很长一段时间才能找到答案。(...而且我认为使用不同于JSF的默认值相当不明智!)


6
PrimeFaces的默认process值为@form。因此,如果不是以这种方式调用操作,而是在使用时调用@this,则很可能适用我的答案的第3点。
BalusC 2013年

3
不能这样 在p:commandButton添加之前,我没有调用actionListener方法process="@this"。此外,《 PrimeFaces用户指南》明确列出了我在3.18和3.19节中提到的默认设置。它在这里:primefaces.googlecode.com/files/primefaces_users_guide_3_4.pdf ...也许默认值已更改?
卡乌

8
文档中可能有错误。删除process="@this"并添加<p:messages autoUpdate="true">(或仅读取服务器日志以获取排队但未显示的消息),您将看到实际上发生了转换/验证错误。
BalusC 2013年

你为什么要删除这个问题stackoverflow.com/questions/60673695/...
Kukeltje

我认为它现在可能没有太大价值……我未删除它。
卡乌

9

我还要提到与Primefaces有关的另一件事p:commandButton

当您将a p:commandButton用于需要在服务器上完成的操作时,您将无法使用,type="button"因为那是用于按钮的按钮,这些按钮用于执行自定义javascript,而不会引起对服务器的ajax / non-ajax请求。

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

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


这是我在其中一页中遇到的主要问题,被接受的答案没有一个点使我们更加接近,您在哪里找到了这些信息?
Uriel Arvizu 2015年

好吧,我已经遇到过很多次这个问题,并且我进行了研究,发现它p:commandButton具有type属性的多个值,并且button是与客户端有关的所有问题。这是一个有点难以找到这个在Primefaces文档,但这里是一个链接:developer.am/primefaces/...
akelec

您的提交提示解决了我几天来一直面临的问题。非常感谢您的帖子!
gpuk360

谢谢,这是我的荣幸。我故意提出这个答案,因为我们很多人都有这样的问题。我也失去了几天,直到意识到发生了什么。
akelec'5

3

我自己陷入了这个问题,并找到了导致该问题的另一个原因。如果在后备bean中没有用于* .xhtml中使用的属性的setter方法,则根本不会调用该操作。


5
这本来应该是不解自明的PropertyNotWritableException。如果没有看到,也许您在没有适当的ajax异常处理程序的情况下触发了一个ajax请求,但是您应该在服务器日志中看到它。
BalusC

3
在我进行p:commandButton的ajax =“ false”之前,它没有显示该异常。
Dnavir

谢谢你救了我的命
exrezzo

3

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

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

我有一个下拉组件,用于选择要显示的行数。支持该字段的值为in RequestScope。支持表本身的数据是某种形式的ViewScope(实际上是,临时存在SessionScope)。

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

将此属性放在与表数据本身相同的作用域中可以解决此问题。

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


2

我也遇到了这个问题,只有在打开浏览器的Web控制台后才真正着手解决根本问题。在此之前,我无法获得任何错误消息(即使使用也不可以<p:messages>)。Web控制台显示了来自的HTTP 405状态代码<h:commandButton type="submit" action="#{myBean.submit}">

就我而言,我混合使用了普通的HttpServlet通过Auth0和JSF facelets提供OAuth身份验证,并且执行我的应用程序视图和业务逻辑的bean。

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

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

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

我不知道的是为什么facelet可以访问bean属性却不能设置它们,而这显然使servlet和JSF的混合消失了,但是我希望这可以帮助某人避免花费很多时间到桌子撞。


1

调试问题时,我的工作很有趣,其中<h:commandLink>的动作被richfaces datatable拒绝触发。该表曾经在某个时候可以工作,但没有明显的原因停止。我毫不动摇,只是发现我rich:datatable使用了错误的方法rowKeyConverter,该方法返回了空值,这些空值被richfaces愉快地用作行键。这阻止了我的<h:commandLink>举动。



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

这是> 600最高答案中的第一名。无需将其编写为单独的答案。
Kukeltje,

-1

这是为我工作的解决方案。

<p:commandButton id="b1" value="Save" process="userGroupSetupForm"
                    actionListener="#{userGroupSetupController.saveData()}" 
                    update="growl userGroupList userGroupSetupForm" />

在这里,对于Ajax调用,必须使用process =“ userGroupSetupForm”属性。actionListener正在从@ViewScope Bean调用方法。还更新咆哮消息,数据表:userGroupList和窗体:userGroupSetupForm。


-2
<ui:composition>  
  <h:form id="form1">
    <p:dialog id="dialog1">
      <p:commandButton value="Save" action="#{bean.method1}" /> <!--Working-->
    </p:dialog>
  </h:form>

  <h:form id="form2">
    <p:dialog id="dialog2">
      <p:commandButton value="Save" action="#{bean.method2}" /> <!--Not Working-->
    </p:dialog>
  </h:form>
</ui:composition>

解决

<ui:composition>  
  <h:form id="form1">
    <p:dialog id="dialog1">
      <p:commandButton value="Save" action="#{bean.method1}" />   <!-- Working  -->
    </p:dialog>

    <p:dialog id="dialog2">
      <p:commandButton value="Save" action="#{bean.method2}" />   <!--Working  -->
    </p:dialog>
  </h:form>
  <h:form id="form2">
    <!-- ..........  -->
  </h:form>
</ui:composition>

抱歉,但这在我的拙见中完全不正确。您有效地指出,两个对话框必须采用其自身的形式才能起作用。您有99%的把握已经解决了一个不同的问题,现在您认为这是解决问题的方法……
Kukeltje

这是包含的页面。也许这可能会引起问题。您应该在投票前对其进行测试。
KenanGökbak19年

不,您应该在发布之前创建一个 最小的可复制示例(只有这样我才能测试)...是的包含可能导致对话框和表单出现问题,但是问题仍然不是您似乎想在此处解决的问题。您的第一个例子非常好,第二个例子具有100%的确定性,不能解决一个不存在的问题
Kukeltje

无论如何。我的应用程序运行正常。我认为对话框中对话框的位置并不重要。我必须创建第二种形式来解决另一个问题。
KenanGökbak'19年

您的应用程序可能正在运行,但是从原始问题和您的“解决方案”中看不出来/看不到。此外,您说_“我认为对话框中表格的位置并不重要。” _但在您的回答中,对话框的位置似乎很重要。一个支持我的陈述的矛盾。抱歉,您的答案很明显是错误的……(已经有另一张
反对票
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.