未调用commandButton/commandLink/ajax操作/侦听器方法或未设置/更新输入值 [英] commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
问题描述
有时,当使用<h:commandLink>
,<h:commandButton>
或<f:ajax>
时,根本不会调用与该标签关联的action
,actionListener
或listener
方法.或者,不使用提交的UIInput
值更新Bean属性.
可能的原因和解决方案是什么?
简介
每当UICommand
组件(<h:commandXxx>
,<p:commandXxx>
等)未能调用关联的操作方法,或UIInput
组件(<h:inputXxx>
,<p:inputXxxx>
等)未能处理提交的内容时值和/或更新模型值,并且在服务器日志中看不到任何可谷歌搜索的异常和/或警告,在按照属性,否则它将是一个无效按钮,仅对JavaScript onclick
有用.另请参见如何发送表格输入值并在JSF bean中调用方法和< h:commandButton>不会发起回发.
您不能相互嵌套多个UIForm
组件.这在HTML中是非法的.浏览器行为未指定.当心包含文件!您可以并行使用UIForm
组件,但是它们在提交期间不会相互处理.您还应该提防上帝形态"反模式;请确保您不会无意间以相同的形式处理/验证所有其他(不可见的)输入(例如,具有相同格式的必填输入的隐藏对话框).另请参见如何使用< h:form>在JSF页面中?单一表格?多种形式?嵌套表格?.
应该没有发生UIInput
值验证/转换错误.您可以使用<h:messages>
显示任何特定于输入的<h:message>
组件未显示的消息.不要忘记将<h:messages>
的id
包含在<f:ajax render>
中(如果有的话),这样它也将根据ajax请求进行更新.另请参见 h:messages在显示p:commandButton时不显示消息按下.
如果将UICommand
或UIInput
组件放置在迭代组件中,例如<h:dataTable>
,<ui:repeat>
等,则需要确保与迭代组件完全相同的value
在表单提交请求的应用请求值阶段保留. JSF将在其上重申以找到单击的链接/按钮和提交的输入值.将bean放在视图范围内和/或确保将数据模型加载到bean的@PostConstruct
中(因此不在getter方法中!)应该对其进行修复.另请参见>如何以及何时从数据库加载模型用于h:dataTable .
如果动态源(例如<ui:include src="#{bean.include}">
)包含UICommand
或UIInput
组件,则需要确保在表单的视图构建期间保留完全相同的#{bean.include}
值.提交请求. JSF将在构建组件树期间重新执行它.将bean放在视图范围内和/或确保将数据模型加载到bean的@PostConstruct
中(因此不在getter方法中!)应该对其进行修复.另请参见如何进行ajax刷新动态通过导航菜单包含内容? (JSF SPA).
在组件的应用请求值阶段,组件及其所有父项的rendered
属性以及任何父项<c:if>
/<c:when>
的test
属性不应评估为false
.表单提交请求. JSF将对其进行重新检查,以作为防止被篡改/被黑客入侵的保护措施的一部分.将负责该条件的变量存储在@ViewScoped
Bean中,或者确保已正确地在@RequestScoped
Bean的@PostConstruct
中预先初始化了该条件,可以对其进行修复.组件的disabled
属性也是如此,在应用请求值阶段期间不应将其评估为true
.另请参见未调用JSF CommandButton操作和向PrimeFaces添加jQuery会导致Uncaught TypeErrors .
如果您通过JSF 2.x <f:ajax>
或例如使用Ajax PrimeFaces <p:commandXxx>
,请确保主模板中有<h:head>
,而不是<head>
.否则,JSF将无法自动包含包含Ajax函数的必要JavaScript文件.这将导致JavaScript错误,例如在浏览器的JS控制台中出现未定义mojarra"或未定义PrimeFaces".另请参见 h:在以下情况下未调用commandLink actionlistener与f:ajax和ui:repeat 一起使用.
如果您使用的是Ajax,并且提交的值最终为null
,请确保感兴趣的UIInput
和UICommand
组件被<f:ajax execute>
覆盖,例如<p:commandXxx process>
,否则将不会执行/处理它们.另请参见添加< f:ajax>时的模型到< h:commandButton> 和了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性.
如果提交的值最终仍然是null
,并且您正在使用CDI管理Bean,请确保从正确的包中导入范围注释,否则CDI将默认为@Dependent
它会在每次对EL表达式求值时有效地重新创建bean.另请参见 @SessionScoped bean释放了范围并一直被重新创建,字段变为空和 JSF规范问题790 ,目前已在JSF 2.3中修复.对于较旧的JSF版本,您需要在<f:ajax>
的render
中明确指定<h:form>
的ID.另请参见 h:commandButton/h: commandLink在第一次单击时不起作用,仅在第二次单击时起作用..
如果<h:form>
设置了enctype="multipart/form-data"
以支持文件上传,那么您需要确保至少使用JSF 2.2,或者要确保负责解析多部分内容的servlet过滤器/form-data请求已正确配置,否则FacesServlet
最终将根本不获取任何请求参数,因此无法应用请求值.如何配置此类过滤器取决于所使用的文件上传组件.对于战斧<t:inputFileUpload>
,请检查此答案,对于PrimeFaces
确保actionListener
的ActionEvent
自变量是javax.faces.event.ActionEvent
,而不是java.awt.event.ActionEvent
,这是大多数IDE建议的第一种自动完成选项.如果使用actionListener="#{bean.method}"
,则没有参数也是错误的.如果您不想在方法中使用参数,请使用actionListener="#{bean.method()}"
.或者,也许您实际上是想使用action
而不是actionListener
.另请参见 action和actionListener之间的差异.
确保在请求-响应链中没有任何PhaseListener
或任何EventListener
更改了JSF生命周期以通过例如调用FacesContext#renderResponse()
或FacesContext#responseComplete()
来跳过调用操作阶段.
确保同一请求-响应链中没有任何Filter
或Servlet
阻止了FacesServlet
的请求.
如果使用的是PrimeFaces <p:dialog>
或<p:overlayPanel>
,请确保它们具有自己的<h:form>
.因为,默认情况下,JavaScript将这些组件重定位到HTML <body>
的末尾.因此,如果他们最初坐在<form>
中,那么现在他们将不再坐在<form>
中.另请参见 p:commandbutton操作在p:dialog内不起作用
该框架中的错误.例如,当在rich:calendar
UI元素中使用rich:calendar
UI元素时,RichFaces会出现"转换错误". defaultLabel
属性(或在某些情况下为rich:placeholder
子元素).当没有为日历日期设置任何值时,此错误阻止Bean方法被调用.跟踪框架的错误可以通过从一个简单的工作示例开始并备份页面直到发现该错误来完成.
调试提示
以防万一,您该进行调试了.在客户端,按Web浏览器中的F12打开Web开发人员工具集.点击控制台标签,然后查看JavaScript控制台.它应该没有任何JavaScript错误.下面的屏幕快照是来自Chrome的示例,演示了在未声明<h:head>
的情况下提交启用<f:ajax>
的按钮的情况(如以上第7点所述).
点击网络标签,以查看HTTP流量监视器.提交表单并调查请求标题和表单数据以及响应正文是否符合预期.下面的屏幕快照是一个来自Chrome的示例,该示例演示了一个简单表单的成功ajax提交,该表单带有一个<h:inputText>
和一个<h:commandButton>
和一个<f:ajax execute="@form" render="@form">
.
(警告:当您在生产环境中通过HTTP请求标头发布屏幕快照时,请确保对屏幕快照中的所有会话cookie进行加扰/混淆,以避免会话劫持攻击!) >
在服务器端,请确保服务器以调试模式启动.将调试断点放在感兴趣的JSF组件的方法中,您希望在处理表单提交期间调用该方法.例如.如果是UICommand
组件,则为 UIInput#validate()
.只需逐步执行代码并检查流程和变量是否符合预期即可.屏幕截图下方是Eclipse调试器的示例.
Sometimes, when using <h:commandLink>
, <h:commandButton>
or <f:ajax>
, the action
, actionListener
or listener
method associated with the tag are simply not being invoked. Or, the bean properties are not updated with submitted UIInput
values.
What are the possible causes and solutions for this?
Introduction
Whenever an UICommand
component (<h:commandXxx>
, <p:commandXxx>
, etc) fails to invoke the associated action method, or an UIInput
component (<h:inputXxx>
, <p:inputXxxx>
, etc) fails to process the submitted values and/or update the model values, and you aren't seeing any googlable exceptions and/or warnings in the server log, also not when you configure an ajax exception handler as per Exception handling in JSF ajax requests, nor when you set below context parameter in web.xml
,
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
and you are also not seeing any googlable errors and/or warnings in browser's JavaScript console (press F12 in Chrome/Firefox23+/IE9+ to open the web developer toolset and then open the Console tab), then work through below list of possible causes.
Possible causes
UICommand
andUIInput
components must be placed inside anUIForm
component, e.g.<h:form>
(and thus not plain HTML<form>
), otherwise nothing can be sent to the server.UICommand
components must also not havetype="button"
attribute, otherwise it will be a dead button which is only useful for JavaScriptonclick
. See also How to send form input values and invoke a method in JSF bean and <h:commandButton> does not initiate a postback.You cannot nest multiple
UIForm
components in each other. This is illegal in HTML. The browser behavior is unspecified. Watch out with include files! You can useUIForm
components in parallel, but they won't process each other during submit. You should also watch out with "God Form" antipattern; make sure that you don't unintentionally process/validate all other (invisible) inputs in the very same form (e.g. having a hidden dialog with required inputs in the very same form). See also How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?.No
UIInput
value validation/conversion error should have occurred. You can use<h:messages>
to show any messages which are not shown by any input-specific<h:message>
components. Don't forget to include theid
of<h:messages>
in the<f:ajax render>
, if any, so that it will be updated as well on ajax requests. See also h:messages does not display messages when p:commandButton is pressed.If
UICommand
orUIInput
components are placed inside an iterating component like<h:dataTable>
,<ui:repeat>
, etc, then you need to ensure that exactly the samevalue
of the iterating component is been preserved during the apply request values phase of the form submit request. JSF will reiterate over it to find the clicked link/button and submitted input values. Putting the bean in the view scope and/or making sure that you load the data model in@PostConstruct
of the bean (and thus not in a getter method!) should fix it. See also How and when should I load the model from database for h:dataTable.If
UICommand
orUIInput
components are included by a dynamic source such as<ui:include src="#{bean.include}">
, then you need to ensure that exactly the same#{bean.include}
value is preserved during the view build time of the form submit request. JSF will reexecute it during building the component tree. Putting the bean in the view scope and/or making sure that you load the data model in@PostConstruct
of the bean (and thus not in a getter method!) should fix it. See also How to ajax-refresh dynamic include content by navigation menu? (JSF SPA).The
rendered
attribute of the component and all of its parents and thetest
attribute of any parent<c:if>
/<c:when>
should not evaluate tofalse
during the apply request values phase of the form submit request. JSF will recheck it as part of safeguard against tampered/hacked requests. Storing the variables responsible for the condition in a@ViewScoped
bean or making sure that you're properly preinitializing the condition in@PostConstruct
of a@RequestScoped
bean should fix it. The same applies to thedisabled
attribute of the component, which should not evaluate totrue
during apply request values phase. See also JSF CommandButton action not invoked and Form submit in conditionally rendered component is not processed.The
onclick
attribute of theUICommand
component and theonsubmit
attribute of theUIForm
component should not returnfalse
or cause a JavaScript error. There should in case of<h:commandLink>
or<f:ajax>
also be no JS errors visible in the browser's JS console. Usually googling the exact error message will already give you the answer. See also Adding jQuery to PrimeFaces results in Uncaught TypeErrors.If you're using Ajax via JSF 2.x
<f:ajax>
or e.g. PrimeFaces<p:commandXxx>
, make sure that you have a<h:head>
in the master template instead of the<head>
. Otherwise JSF won't be able to auto-include the necessary JavaScript files which contains the Ajax functions. This would result in a JavaScript error like "mojarra is not defined" or "PrimeFaces is not defined" in browser's JS console. See also h:commandLink actionlistener is not invoked when used with f:ajax and ui:repeat.If you're using Ajax, and the submitted values end up being
null
, then make sure that theUIInput
andUICommand
components of interest are covered by the<f:ajax execute>
or e.g.<p:commandXxx process>
, otherwise they won't be executed/processed. See also Submitted form values not updated in model when adding <f:ajax> to <h:commandButton> and Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes.If the submitted values still end up being
null
, and you're using CDI to manage beans, then make sure that you import the scope annotation from the correct package, else CDI will default to@Dependent
which effectively recreates the bean on every single evaluation of the EL expression. See also @SessionScoped bean looses scope and gets recreated all the time, fields become null and What is the default Managed Bean Scope in a JSF 2 application?If a parent of the
<h:form>
with theUICommand
button is beforehand been rendered/updated by an ajax request coming from another form in the same page, then the first action will always fail in JSF 2.2 or older. The second and subsequent actions will work. This is caused by a bug in view state handling which is reported as JSF spec issue 790 and currently fixed in JSF 2.3. For older JSF versions, you need to explicitly specify the ID of the<h:form>
in therender
of the<f:ajax>
. See also h:commandButton/h:commandLink does not work on first click, works only on second click.If the
<h:form>
hasenctype="multipart/form-data"
set in order to support file uploading, then you need to make sure that you're using at least JSF 2.2, or that the servlet filter who is responsible for parsing multipart/form-data requests is properly configured, otherwise theFacesServlet
will end up getting no request parameters at all and thus not be able to apply the request values. How to configure such a filter depends on the file upload component being used. For Tomahawk<t:inputFileUpload>
, check this answer and for PrimeFaces<p:fileUpload>
, check this answer. Or, if you're actually not uploading a file at all, then remove the attribute altogether.Make sure that the
ActionEvent
argument ofactionListener
is anjavax.faces.event.ActionEvent
and thus notjava.awt.event.ActionEvent
, which is what most IDEs suggest as 1st autocomplete option. Having no argument is wrong as well if you useactionListener="#{bean.method}"
. If you don't want an argument in your method, useactionListener="#{bean.method()}"
. Or perhaps you actually want to useaction
instead ofactionListener
. See also Differences between action and actionListener.Make sure that no
PhaseListener
or anyEventListener
in the request-response chain has changed the JSF lifecycle to skip the invoke action phase by for example callingFacesContext#renderResponse()
orFacesContext#responseComplete()
.Make sure that no
Filter
orServlet
in the same request-response chain has blocked the request fo theFacesServlet
somehow.If you are using a PrimeFaces
<p:dialog>
or a<p:overlayPanel>
, then make sure that they have their own<h:form>
. Because, these components are by default by JavaScript relocated to end of HTML<body>
. So, if they were originally sitting inside a<form>
, then they would now not anymore sit in a<form>
. See also p:commandbutton action doesn't work inside p:dialogBug in the framework. For example, RichFaces has a "conversion error" when using a
rich:calendar
UI element with adefaultLabel
attribute (or, in some cases, arich:placeholder
sub-element). This bug prevents the bean method from being invoked when no value is set for the calendar date. Tracing framework bugs can be accomplished by starting with a simple working example and building the page back up until the bug is discovered.
Debugging hints
In case you still stucks, it's time to debug. In the client side, press F12 in webbrowser to open the web developer toolset. Click the Console tab so see the JavaScript conosle. It should be free of any JavaScript errors. Below screenshot is an example from Chrome which demonstrates the case of submitting an <f:ajax>
enabled button while not having <h:head>
declared (as described in point 7 above).
Click the Network tab to see the HTTP traffic monitor. Submit the form and investigate if the request headers and form data and the response body are as per expectations. Below screenshot is an example from Chrome which demonstrates a successful ajax submit of a simple form with a single <h:inputText>
and a single <h:commandButton>
with <f:ajax execute="@form" render="@form">
.
(warning: when you post screenshots from HTTP request headers like above from a production environment, then make sure you scramble/obfuscate any session cookies in the screenshot to avoid session hijacking attacks!)
In the server side, make sure that server is started in debug mode. Put a debug breakpoint in a method of the JSF component of interest which you expect to be called during processing the form submit. E.g. in case of UICommand
component, that would be UICommand#queueEvent()
and in case of UIInput
component, that would be UIInput#validate()
. Just step through the code execution and inspect if the flow and variables are as per expectations. Below screenshot is an example from Eclipse's debugger.
这篇关于未调用commandButton/commandLink/ajax操作/侦听器方法或未设置/更新输入值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!