What is the difference between action
and actionListener
, and when should I use action
versus actionListener
?
Differences between action and actionListener
actionactionlistenerjsfjsf-2
Related Solutions
JSP (JavaServer Pages)
JSP is a Java view technology running on the server machine which allows you to write template text in client side languages (like HTML, CSS, JavaScript, ect.). JSP supports taglibs, which are backed by pieces of Java code that let you control the page flow or output dynamically. A well-known taglib is JSTL. JSP also supports Expression Language, which can be used to access backend data (via attributes available in the page, request, session and application scopes), mostly in combination with taglibs.
When a JSP is requested for the first time or when the web app starts up, the servlet container will compile it into a class extending HttpServlet
and use it during the web app's lifetime. You can find the generated source code in the server's work directory. In for example Tomcat, it's the /work
directory. On a JSP request, the servlet container will execute the compiled JSP class and send the generated output (usually just HTML/CSS/JS) through the web server over a network to the client side, which in turn displays it in the web browser.
Servlets
Servlet is a Java application programming interface (API) running on the server machine, which intercepts requests made by the client and generates/sends a response. A well-known example is the HttpServlet
which provides methods to hook on HTTP requests using the popular HTTP methods such as GET
and POST
. You can configure HttpServlet
s to listen to a certain HTTP URL pattern, which is configurable in web.xml
, or more recently with Java EE 6, with @WebServlet
annotation.
When a Servlet is first requested or during web app startup, the servlet container will create an instance of it and keep it in memory during the web app's lifetime. The same instance will be reused for every incoming request whose URL matches the servlet's URL pattern. You can access the request data by HttpServletRequest
and handle the response by HttpServletResponse
. Both objects are available as method arguments inside any of the overridden methods of HttpServlet
, such as doGet()
and doPost()
.
JSF (JavaServer Faces)
JSF is a component based MVC framework which is built on top of the Servlet API and provides components via taglibs which can be used in JSP or any other Java based view technology such as Facelets. Facelets is much more suited to JSF than JSP. It namely provides great templating capabilities such as composite components, while JSP basically only offers the <jsp:include>
for templating in JSF, so that you're forced to create custom components with raw Java code (which is a bit opaque and a lot of tedious work) when you want to replace a repeated group of components with a single component. Since JSF 2.0, JSP has been deprecated as view technology in favor of Facelets.
Note: JSP itself is NOT deprecated, just the combination of JSF with JSP is deprecated.
Note: JSP has great templating abilities by means of Taglibs, especially the (Tag File) variant. JSP templating in combination with JSF is what is lacking.
As being a MVC (Model-View-Controller) framework, JSF provides the FacesServlet
as the sole request-response Controller. It takes all the standard and tedious HTTP request/response work from your hands, such as gathering user input, validating/converting them, putting them in model objects, invoking actions and rendering the response. This way you end up with basically a JSP or Facelets (XHTML) page for View and a JavaBean class as Model. The JSF components are used to bind the view with the model (such as your ASP.NET web control does) and the FacesServlet
uses the JSF component tree to do all the work.
Related questions
- What is the main-stream Java alternative to ASP.NET / PHP?
- Java EE web development, what skills do I need?
- How do servlets work? Instantiation, session variables and multithreading
- What is a Javabean and where are they used?
- How to avoid Java code in JSP files?
- What components are MVC in JSF MVC framework?
- What is the need of JSF, when UI can be achieved with JavaScript libraries such as jQuery and AngularJS
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
andreadonly
attributes of the component, which should not evaluate totrue
during apply request values phase. See also JSF CommandButton action not invoked, Form submit in conditionally rendered component is not processed, h:commandButton is not working once I wrap it in a <h:panelGroup rendered> and Force JSF to process, validate and update readonly/disabled input components anywayThe
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 Manually adding / loading jQuery with 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. For example, login/security filters such as Spring Security. Particularly in ajax requests that would by default end up with no UI feedback at all. See also Spring Security 4 and PrimeFaces 5 AJAX request handling.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.
Best Answer
actionListener
Use
actionListener
if you want have a hook before the real business action get executed, e.g. to log it, and/or to set an additional property (by<f:setPropertyActionListener>
), and/or to have access to the component which invoked the action (which is available byActionEvent
argument). So, purely for preparing purposes before the real business action gets invoked.The
actionListener
method has by default the following signature:And it's supposed to be declared as follows, without any method parentheses:
Note that you can't pass additional arguments by EL 2.2. You can however override the
ActionEvent
argument altogether by passing and specifying custom argument(s). The following examples are valid:Note the importance of the parentheses in the argumentless method expression. If they were absent, JSF would still expect a method with
ActionEvent
argument.If you're on EL 2.2+, then you can declare multiple action listener methods via
<f:actionListener binding>
.Note the importance of the parentheses in the
binding
attribute. If they were absent, EL would confusingly throw ajavax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, because thebinding
attribute is by default interpreted as a value expression, not as a method expression. Adding EL 2.2+ style parentheses transparently turns a value expression into a method expression. See also a.o. Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?action
Use
action
if you want to execute a business action and if necessary handle navigation. Theaction
method can (thus, not must) return aString
which will be used as navigation case outcome (the target view). A return value ofnull
orvoid
will let it return to the same page and keep the current view scope alive. A return value of an empty string or the same view ID will also return to the same page, but recreate the view scope and thus destroy any currently active view scoped beans and, if applicable, recreate them.The
action
method can be any validMethodExpression
, also the ones which uses EL 2.2 arguments such as below:With this method:
Note that when your action method solely returns a string, then you can also just specify exactly that string in the
action
attribute. Thus, this is totally clumsy:With this senseless method returning a hardcoded string:
Instead, just put that hardcoded string directly in the attribute:
Please note that this in turn indicates a bad design: navigating by POST. This is not user nor SEO friendly. This all is explained in When should I use h:outputLink instead of h:commandLink? and is supposed to be solved as
See also How to navigate in JSF? How to make URL reflect current page (and not previous one).
f:ajax listener
Since JSF 2.x there's a third way, the
<f:ajax listener>
.The
ajaxListener
method has by default the following signature:In Mojarra, the
AjaxBehaviorEvent
argument is optional, below works as good.But in MyFaces, it would throw a
MethodNotFoundException
. Below works in both JSF implementations when you want to omit the argument.Ajax listeners are not really useful on command components. They are more useful on input and select components
<h:inputXxx>
/<h:selectXxx>
. In command components, just stick toaction
and/oractionListener
for clarity and better self-documenting code. Moreover, likeactionListener
, thef:ajax listener
does not support returning a navigation outcome.For explanation on
execute
andrender
attributes, head to Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes.Invocation order
The
actionListener
s are always invoked before theaction
in the same order as they are been declared in the view and attached to the component. Thef:ajax listener
is always invoked before any action listener. So, the following example:Will invoke the methods in the following order:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Exception handling
The
actionListener
supports a special exception:AbortProcessingException
. If this exception is thrown from anactionListener
method, then JSF will skip any remaining action listeners and the action method and proceed to render response directly. You won't see an error/exception page, JSF will however log it. This will also implicitly be done whenever any other exception is being thrown from anactionListener
. So, if you intend to block the page by an error page as result of a business exception, then you should definitely be performing the job in theaction
method.If the sole reason to use an
actionListener
is to have avoid
method returning to the same page, then that's a bad one. Theaction
methods can perfectly also returnvoid
, on the contrary to what some IDEs let you believe via EL validation. Note that the PrimeFaces showcase examples are littered with this kind ofactionListener
s over all place. This is indeed wrong. Don't use this as an excuse to also do that yourself.In ajax requests, however, a special exception handler is needed. This is regardless of whether you use
listener
attribute of<f:ajax>
or not. For explanation and an example, head to Exception handling in JSF ajax requests.