Calling bean methods with arguments from JSF pages - jsf

Is it possible to call bean methods & directly pass parameters to them from the view instead of requiring to first set the bean properties and then call methods without arguments using the commandButton or similar ?
I have a list of items with each item having a list of actions. To reduce the state, I am using a single primefaces remoteCommand, in place of several commandButton(s). On getting a action trigger from the view, I would call the remoteCommand from javascript but since the remoteCommand is one but used for multiple items thus I need to pass the id of the item as well. I am wondering if there is a way to pass the id of the item to the bean method directly as an argument instead of first setting it as a bean property ? Is there any way to do so ?
Actually I am looking at a better way to deal with multiple commandButtons on a page when there's a long list of items on the page.
Suggestions ? Thanks.
Using JSF 2.1.6 Mojarra with Primefaces 3.0RC1

Passing method arguments is supported since EL 2.2 which is part of Servlet 3.0. So if your webapp runs on a Servlet 3.0 compatible container (Tomcat 7, Glassfish 3, etc) with a web.xml declared conform Servlet 3.0 spec (which is likely true as you're using JSF 2.1 which in turn implicitly requires Servlet 3.0), then you will be able to pass method arguments to bean action methods in the following form:
<h:commandButton value="Submit" action="#{bean.submit(item.id)}" />
with
public void submit(Long id) {
// ...
}
You can even pass fullworthy objects along like as:
<h:commandButton value="Submit" action="#{bean.submit(item)}" />
with
public void submit(Item item) {
// ...
}
If you were targeting a Servlet 2.5 container, then you could achieve the same by replacing the EL implementation by for example JBoss EL which supports the same construct. See also Invoke direct methods or methods with arguments / variables / parameters in EL.

Yes, it is.
<h:commandButton action="#{bean.method(object)}" />
See this http://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/

You can call ManagedBean methods with arguments like this.
<h:commandButton actionListener="#{stateBean.delete(row.stateID)}"
value="Delete" id="btnDeleteS">
<f:ajax event="action" execute="#form" render="#form"/>
</h:commandButton>
The corresponding ManagedBean would be like this.
#ManagedBean
#RequestScoped
public class StateBean
{
#EJB
private RemoteInterface obj=null;
public void delete(String stateID)
{
//Code stuff here.
}
}
You can also directly set the value of ManagedBean properties using <f:setPropertyActionListener></f:setPropertyActionListener> like this.
<h:commandButton value="Delete" id="btnDeleteS">
<f:setPropertyActionListener target="#{stateBean.someProperty}"
value="#{someValue}"/>
<f:ajax event="action" execute="#form" render="#form"/>
</h:commandButton>

Related

Linking entities in different JSF pages [duplicate]

What is the difference between action and actionListener, and when should I use action versus actionListener?
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 by ActionEvent argument). So, purely for preparing purposes before the real business action gets invoked.
The actionListener method has by default the following signature:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
And it's supposed to be declared as follows, without any method parentheses:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
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:
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
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>.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
Note the importance of the parentheses in the binding attribute. If they were absent, EL would confusingly throw a javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean, because the binding 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. The action method can (thus, not must) return a String which will be used as navigation case outcome (the target view). A return value of null or void 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 valid MethodExpression, also the ones which uses EL 2.2 arguments such as below:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
With this method:
public void edit(Item item) {
// ...
}
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:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
With this senseless method returning a hardcoded string:
public String goToNextpage() {
return "nextpage";
}
Instead, just put that hardcoded string directly in the attribute:
<h:commandLink value="Go to next page" action="nextpage" />
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
<h:link value="Go to next page" outcome="nextpage" />
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>.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
The ajaxListener method has by default the following signature:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
In Mojarra, the AjaxBehaviorEvent argument is optional, below works as good.
public void ajaxListener() {
// ...
}
But in MyFaces, it would throw a MethodNotFoundException. Below works in both JSF implementations when you want to omit the argument.
<h:commandXxx ...>
<f:ajax execute="#form" listener="#{bean.ajaxListener()}" render="#form" />
</h:commandXxx>
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 to action and/or actionListener for clarity and better self-documenting code. Moreover, like actionListener, the f:ajax listener does not support returning a navigation outcome.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="#form" render="#form" />
</h:commandXxx>
For explanation on execute and render attributes, head to Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes.
Invocation order
The actionListeners are always invoked before the action in the same order as they are been declared in the view and attached to the component. The f:ajax listener is always invoked before any action listener. So, the following example:
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
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 an actionListener 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 an actionListener. 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 the action method.
If the sole reason to use an actionListener is to have a void method returning to the same page, then that's a bad one. The action methods can perfectly also return void, on the contrary to what some IDEs let you believe via EL validation. Note that the PrimeFaces showcase examples are littered with this kind of actionListeners 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.
As BalusC indicated, the actionListener by default swallows exceptions, but in JSF 2.0 there is a little more to this. Namely, it doesn't just swallows and logs, but actually publishes the exception.
This happens through a call like this:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
The default listener for this event is the ExceptionHandler which for Mojarra is set to com.sun.faces.context.ExceptionHandlerImpl. This implementation will basically rethrow any exception, except when it concerns an AbortProcessingException, which is logged. ActionListeners wrap the exception that is thrown by the client code in such an AbortProcessingException which explains why these are always logged.
This ExceptionHandler can be replaced however in faces-config.xml with a custom implementation:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Instead of listening globally, a single bean can also listen to these events. The following is a proof of concept of this:
#ManagedBean
#RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
#Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(note, this is not how one should normally code listeners, this is only for demonstration purposes!)
Calling this from a Facelet like this:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Will result in an error page being displayed.
ActionListener gets fired first, with an option to modify the response, before Action gets called and determines the location of the next page.
If you have multiple buttons on the same page which should go to the same place but do slightly different things, you can use the same Action for each button, but use a different ActionListener to handle slightly different functionality.
Here is a link that describes the relationship:
http://www.java-samples.com/showtutorial.php?tutorialid=605
TL;DR:
The ActionListeners (there can be multiple) execute in the order they were registered BEFORE the action
Long Answer:
A business action typically invokes an EJB service and if necessary also sets the final result and/or navigates to a different view
if that is not what you are doing an actionListener is more appropriate i.e. for when the user interacts with the components, such as h:commandButton or h:link they can be handled by passing the name of the managed bean method in actionListener attribute of a UI Component or to implement an ActionListener interface and pass the implementation class name to actionListener attribute of a UI Component.

How to use component binding in JSF right ? (request-scoped component in session scoped bean)

Mojara 2.1.21
I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)
Version 1:
single.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 2:
template.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}"
view1.xhtml:
<ui:composition template="template.xhtml" />
view2.xhtml:
<ui:composition template="template.xhtml" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ?
Is it safe to use (request-scoped) component (in version 1) with session scoped binding ?
Are there another use cases to consider ?
Edit:
Functional requirement 1:
I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.
Functional requirement 2:
Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?
Requirements 3
The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.
In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.
As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:commandLink value="Foo" action="#{bean.foo(item)}" />
The two last requirements are totally unclear. At least, if you're doing something like:
<x:someComponent binding="#{bean.someComponent}" />
with in bean
someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);
then you should instead be doing
<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />
Or, if you intend to be able to use the component somewhere else in the view like so
<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />
and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:
<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />
If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a #ManagedProperty of the request scoped one.
See also:
Binding attribute causes duplicate component ID found in the view
How does the 'binding' attribute work in JSF? When and how should it be used?
We ran into a similar problem and I just want to share our solution:
Problem:
In a view there was a (extended largely customized) datatable.
<x:dataTable binding="#{bean.someSomeDataTable}" />
After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.
public HtmlDataTable getSomeDataTable()
{
HtmlDataTable htmlDataTable = new HtmlDataTable();
if (tableState != null)
htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
return htmlDataTable;
}
public void setSomeDataTable(HtmlDataTable table)
{
tableState = table.saveState(FacesContext.getCurrentInstance());
}

Primefaces commandButton: f:attribute does not work

Project uses Spring Webflow and JSF (PrimeFaces). I have a p:commandButton with f:attribute
<p:commandButton disabled="#{editGroupMode=='edit'}" action="edit_article_group" actionListener="#{articleGroupManager.setSelectedRow}" ajax="false" value="Edit">
<f:attribute name="selectedIndex" value="${rowIndex}" />
</p:commandButton>
Backend code (Spring injected bean):
#Service("articleGroupManager")
public class ArticleGroupManagerImpl implements ArticleGroupManager{
public void setSelectedRow(ActionEvent event) {
String selectedIndex = (String)event.getComponent().getAttributes().get("selectedIndex");
if (selectedIndex == null) {
return;
}
}
}
The attribute "selectedIndex" is always null. Anybody knows what happened here? Thank you.
The variable name "rowIndex" suggests that you've declared this inside an iterating component, such as <p:dataTable>.
This is then indeed not going to work. There's physically only one JSF component in the component tree which is reused multiple times during generating HTML output. The <f:attribute> is evaluated at the moment when the component is created (which happens only once, long before iteration!), not when the component generates HTML based on the currently iterated row. It would indeed always be null.
There are several ways to achieve your concrete functional requirement anyway. The most sane approach would be to just pass it as method argument:
<p:commandButton value="Edit"
action="edit_article_group"
actionListener="#{articleGroupManager.setSelectedRow(rowIndex)}"
ajax="false" disabled="#{editGroupMode=='edit'}" />
with
public void setSelectedRow(Integer rowIndex) {
// ...
}
See also:
JSTL in JSF2 Facelets... makes sense?
How can I pass selected row to commandLink inside dataTable?
Unrelated to the concrete problem, I'd in this particular case have used just a GET link with a request parameter to make the request idempotent (bookmarkable, re-executable without impact in server side, searchbot-crawlable, etc). See also Communication in JSF 2.0 - Processing GET request parameters.

JSF component binding - some confusion

From web pages like this one,
http://www.jsftutorials.net/components/step5.html
I understand that the binding attribute in JSF tag/view component is to bind the view component to a Java instance of the UI component in the backing bean.
E.g., that's what is done in the following code:
<h:inputText value="#{ myBean.someProperty}" binding="#{ myBean.somePropertyInputText}"/>
But sometimes I see code like this:
<h:commandButton id="t1" binding="#{foo}" value="Hello, World!" onclick="alert('I am #{id:cid(foo)}'); return false;" />
where id:cid is a taglib function which is defined as follow:
public static String cid(UIComponent component) {
FacesContext context = FacesContext.getCurrentInstance();
return component.getClientId(context);
}
In the above code, binding="#{foo}" does not bind to "a Java instance of the UI component in the backing bean".
So what is the meaning of expressions such as binding="#{foo}" ?
It just binds the component to the current Facelet scope. This is particularly useful if you don't need it in the backing bean at all. This saves your backing bean code from useless properties which aren't been used in any of the other methods at all. Note that it also works that way in JSF 1.2. Not sure about JSF 1.0/1.1 though as it uses a different and JSF-proprietary EL API.
See also:
JSF component binding without bean property

How to display value of List#size() in JSF EL?

I'd like to know if there's a way to bind the returned value of a method into a JSF component.
I'll explain myself better.
Let's say I have a class like this:
public class Document {
private List<Attachment> attachments;
//getter and setter here
}
this class is exposed to jsf through a registered managed bean in a property called currentDocument, and used in a jsf this way
<h:outputText value="#{myManagedBean.currentDocument.attachment.size}" />
This isn't correct, I know. But what is the correct way to do this?
Am I supposed to create an attribute on the Document class, let's say numberOfAttachments, and bind to that, or there's a way to bind directly on a method's return value?
If you're running an EL 2.2 capable container (Tomcat 7, Glassfish 3, JBoss AS 6 or newer, all implementing Servlet 3.0), or are using JBoss EL, then you should be able to invoke non-getter methods by EL:
<h:outputText value="#{myManagedBean.currentDocument.attachment.size()}" />
An alternative is to use JSTL fn:length():
<html xmlns:fn="http://java.sun.com/jsp/jstl/functions" ...>
...
<h:outputText value="#{fn:length(myManagedBean.currentDocument.attachment)}" />
If none of that is possible for you for some reason, then your best bet is to create an EL function yourself
<h:outputText value="#{my:size(myManagedBean.currentDocument.attachment)}" />
or to add an extra getter method to #{myManagedBean} which returns exactly that.
<h:outputText value="#{myManagedBean.currentDocumentAttachmentSize}" />
See also:
Invoke direct methods or methods with arguments / variables / parameters in EL

Resources