How to call a method when a form is submitted on a JSF page? - jsf

What I basically want to do is, when the user submits the form, a method should be called, which is not a setter.
Here is what I have tried:
<h:form>
<p>
Your guess: <h:inputText value="#{quizBean.someMethod()}"/>
</p>
<p>
<h:commandButton value="Submit answer"/>
</p>
</h:form>
It does not work with #{quizBean.someMethod} either.
If I create a field called someMethod and generate getters and setters for it, it will work fine.
Is there anyway to do this?
My web.xml:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
I am running this on Tomcat 7.0 and using jsf-api:2.1.19 and jsf-impl:2.1.19 jars.
This is the exception I am getting:
javax.servlet.ServletException: /index.xhtml #23,71 value="#{quizBean.someMethod()}": Property 'someMethod' not found on type com.tugay.problems.QuizBean
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)

No.
The value attribute must evaluate to a property expression (with its get method). Moreover, if the control is not readonly, a set method must also be provided.
Other attributes (like the action attribute from h:commandButton) accept expressions that do evaluate to a method in the bean, but not this one.
The only workaround is what you already did, making the get implement someMethod. Be careful that I am not sure the method will be called when rendering a JSF page.

You want to call a method on form submit? This is exactly what h:commandButton is made for. Just add the action attribute to your command button and point it to an action method like this:
<h:inputText value="#{quizBean.answer}"/>
<h:commandButton value="Submit answer" action="#{quizBean.submitAnswer}"/>
The method on your bean should look like this:
public String submitAnswer() {
// Do something with property answer
return null;
}
As the action method is called after the values from the input components are stored, you can access them without problems. The return value is used for navigation by JSF. It can contain a view ID or a navigation outcome. If the return value is null, JSF stays on the same page.

Related

how is the bean accessed first time?

I am going through the tutorial of Java EE 7 in oracle.
Here is a simple form that gets User name in a input box:
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
alt="Duke waving his hand"/>
<h2>Hello, my name is Duke. What's yours?</h2>
<h:inputText id="username"
title="My name is: "
value="#{hello.name}"
required="true"
requiredMessage="Error: A name is required."
maxlength="25" />
<p></p>
<h:commandButton id="submit" value="Submit" action="response">
</h:commandButton>
<h:commandButton id="reset" value="Reset" type="reset">
</h:commandButton>
</h:form>
I see that value="#{hello.name}" is used in the code. what does this line do?
This is what is mentioned in the tutorial link:
The web page connects to the Hello managed bean through the Expression Language (EL) value expression #{hello.name}, which retrieves the value of the name property from the managed bean.
Q1) But the first time the form is loaded, there is no name attribute attached to hello bean. so Fetching that should return null correct?
Q2) Secondly, how does the value entered in the input box bind to the hello bean's name attribute?
In fact, after the form is submitted, the page is redirected to "response.xhtml" where the value of hello bean's name attribute is fetched in the same way i.e #{hello.name}.
Short answer:
Q1: correct
Q2:
On each page rendering elements, bound to #{hello.name} will receive the value, returned by Hello.getName() method.
On each form submit (in case form is valid), Hello.setName(param) will be called with param equals to value of element, bound to #{hello.name}
Longer answer:
You have:
Hello.java, the class annotated with #Named and #RequestScoped
<h:inputText value="#{hello.name}" /> inside <h:form> on index.xhtml
#{hello.name} inside <h2> on response.xhtml
Prerequisites:
#Named is a CDI annotation.
When application is deployed, the server "registers" Hello.java as a managed bean.
#Named could be used as #Named(name="explicitHelloName"), but if argument isn't provided, the bean will be registered as "lower cased class name", so, after your application is deployed, we have hello to be used wherever it needed.
#RequestScoped says that data of each Hello instance will "live" only during request-response (see this answer for scoping details).
This article greatly describes JSF lifecycle. We are interested in two fazes of it:
RENDER_RESPONSE and UPDATE_MODEL_VALUES.
Let's go step by step:
I. Browser requests index.xhtml
FacesServlet's responsibility (because we are mapping all *.xhtml files to Faces Servlet inside web.xml) is to build html and return it as a response.
Building consists of several phases (look here for details), one of which, RENDER-RESPONSE:
Builds a UIViewRoot
Recursively builds UIViewRoot's children.
During 2) for children, that has some EL expressions, these expressions being "resolved".
In your case we have #{hello.name} expression, bound to value of an UIInput (h:inputText is an UIInput).
<h:inputText> will be rendered as HTML's <input type="text">.
FacesServlet "understands" that value for this input should be taken from something that #{hello.name} represents.
To get the value:
FacesServlet "asking" for hello from container (server)
Container searches for registered hello, finding Hello.java, instantiating it and gives to FacesServlet.
FacesServlet calling for getName() (JavaBean convention to get the "name") of Hello instance and receives the value of Hello's private field name, which after class instantiation is null.
FacesServlet writes <input> without value to response and on index.xhtml you see an empty input.
II. When you press submit button
...and form is valid, there is UPDATE_MODEL phase (more detailed here),.
For our h:inputText component FacesServlet again searches for hello, finding an instance of Hello and calls setName(value) on it.
As <h:commandButtons>'s action attribute is response, browser is about to receive response.xhtml's content (this is not a redirection, see this answer, so, #RequestScoped hello isn't being recreated).
III. response.xhtml
...has <h3>Hello, #{hello.name}</h3>, so, again, FacesServlet must resolve it as described earlier.
But in current request the Hellohave been instantiated and it's field name was already set (in UPDATE_MODEL_VALUES phase) with the value you entered to input, so, <h3>Hello, YOUR_SUBMITTED_TO_INPUT_TEXT_VALUE</h3> is written to response and displayed in browser.
More details about expressions can be found here
Edit
If you use <h:comandButton action="response?faces-redirect=true"/> on the index.xhtml, then after II there will be a redirect to response.xhtml, and Hello bean become recreated, so, you will see "Hello, " (name will be null)

commandLink is not fired in a page with a param in its URI

When I call a method in a page with a param in its URI, the method is not invoked unless I pass the parameters of the uri again. For example if I have:
http://maywebsite/myapp/mypage.xhtml?mykey=myvalue
This method results in error (obviously because it renders the page again without params, but the method foo is never invoked):
<h:commandLink value="Do Action" actionListener="#{mybean.foo}"/>
So I added an ajax to only update the component, but the button is not getting fired:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:ajax render="somecomponent"/>
</h:commandLink>
When I passed the param values again, the button invokes the method just fine:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:param name="mykey" value="myvalue"/>
<f:ajax render="somecomponent"/>
</h:commandLink>
However, this button is included (ui:include) in many pages with different param keys and values. How can I invoke the method without passing the param values?
Im using glassfish 3.1.2, jsf 2.0
Apparently the bean is request scoped and the parameter plays a role in the way how the command link is rendered (e.g. by the rendered attribute on one of its parent components, or by a dynamic include of the template containing the command link).
All those conditions are namely re-evaluated during apply request values phase of the form submit. The developer has to make sure that all those conditions are exactly the same as when the form was presented to the enduser. So, when the bean is request scoped and the parameter is absent, then the command link appears as non-rendered in the component tree and this way its action won't be invoked.
Putting the bean in the view scope is the easiest way to fix this (unless you're using a dynamic <ui:include>, this is then more complicated, you'd need to turn off partial state saving for the particular view).
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5

JSF accessing backing map object

I have a jsp subview page that I have passed a parameter to and I want to then pass that parameter to a map's get() method that is stored in a session bean.
Ex:
<h:panelGrid id="panelGrid1" rendered="#{MySessionBean[param.id].showPanelGrid1}">
...
</h:panelGrid>
In the above example MySessionBean implements the Map interface and I have my own custom get method that will create an object and put it in the map if none exists for the key [params.id]. When I run the code in debug mode my get method for MySessionBean never gets called and my panel is always rendered. Am I not passing parameters correctly? Or accessing the parameter passed to the subview correclty?
Here is how I passed the parameter to this subview:
<f:subview id="subview1">
<jsp:include page="/MyTemplatePage.jsp">
<jsp:param name="id" value="staticUniqueId1"/>
</jsp:include>
</f:subview>
The reason I'm trying to do this is so I can include this template subview multiple times in a single page so that each instance won't have the same backing bean objects. Thus using a map in the session and passing it an id to gain access to the backing beans for each instance.
Also, I am limited JSF 1.2, JSTL 1.1, JBoss 4.0.4. So I can't use answers that use RichFaces or JSF 2.
EDIT: 11/22/11 11:23
I Replaced the [param.id] with a static string value.
<h:panelGrid id="panelGrid1" rendered="#{MySessionBean.MY_TEMP_VAL.showPanelGrid1}">
...
</h:panelGrid>
And everything worked. It triggered my map get method and accessed the session beans and everything. So it is clearly not liking the whole using [params.id] passing to the map object. Not sure what to do from here.
In JSF2 the proper and easy solution would be to use composite components. Since you are stuck with JSF 1.2 and jsp you could use tag files instead. These are like regular jsps but with the extension tag or tagx and placed under WEB-INF/tags. I'm using the xml syntax in the example below, in a file name example.tagx:
<jsp:root version="2.1"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:h="http://java.sun.com/jsf/html">
<jsp:directive.attribute name="myBean"
required="true"
rtexprvalue="false"
deferredValue="true"
deferredValueType="com.example.MyBean"/>
<h:panelGrid id="panelGrid1" rendered="#{myBean.showPanelGrid1}">
...
</h:panelGrid>
</jsp:root>
In a jspx you then have to declare the namespace like xmlns:myTags="urn:jsptagdir:/WEB-INF/tags/", in a jsp the syntax would be:
<%#taglib tagdir="/WEB-INF/tags" prefix="myTags" %>
The custom tag can then be used multiple times on a page and the right backing bean can be passed as an attribute like this:
<myTags:example myBean="#{myBeanInstance1}" />
Edit: You might also need a file WEB-INF/tags/implicit.tld to specify the version:
<?xml version = '1.0' encoding = 'UTF-8'?>
<taglib xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1" xmlns="http://java.sun.com/xml/ns/javaee">
<tlib-version>2.1</tlib-version>
</taglib>

JSF2.0, how commandButton knows which bean to send this

I am starting in JSF2, comming from spring mvc, so I have some doubts that I cannot find answers on Core JavaServer Faces v3
Like this one...
How can the tag h:commandButton know which bean I am talking about ? I can only have one Bean per JSF page, is that it ? I am only giving it a msg.next which is a text from a i18n file.(quizbean is my bean)
<h:body>
<h:form>
<h3>#{msgs.heading}</h3>
<p>
<h:outputFormat value="#{msgs.currentScore}">
<f:param value="#{quizBean.score}"/>
</h:outputFormat>
</p>
<p>#{msgs.guessNext}</p>
<p>#{quizBean.current.sequence}</p>
<p>
#{msgs.answer}
<h:inputText value="#{quizBean.answer}"/>
</p>
<p><h:commandButton value="#{msgs.next}"/></p>
</h:form>
The command button does not need to know this. All it generates is a HTML <input type="submit"> element. This is embedded in a HTML <form> with an action URL pointing to the same URL as the page. There's further also the <input type="hidden" name="javax.faces.ViewState">. Thanks to this field, JSF knows exactly what view you're submitting to. This view holds information about all inputs. This view knows that there's an <h:inputText value="#{quizBean.answer}" />. The view knows the field name of the generated HTML <input type="text"> element. JSF will get the submitted request parameter value by request.getParameter() using this name and then update the answer property of the current instance of quizBean with this value.
Rightclick the page in your browser and choose View Source to see the JSF-generated HTML output. Put a breakpoint on ApplyRequestValuesPhase#execute() and HtmlBasicRenderer#decode() methods (assuming that you're using Mojarra not MyFaces) to track the gathering of submitted values for every UIComponent in the view.
The bean has to be managed by JSF, then it will know which bean you are talking about.
e.g.
<f:param value="#{quizBean.score}"/>
Here, the bean quizBean is a Managed-Bean, managed by JSF.
And to make it a managed bean you to tell JSF about it by either using annotations as follows -
#ManagedBean(name="quizBean") //name is optional or you give your own name to the bean
#SessionScoped //tell JSF in which scope you want to keep your managedbean
public class QuizBean {
//....
Or by mentioning it as follows in the JSF configuration file (faces-config.xml) -
<managed-bean>
<managed-bean-name>quizBean</managed-bean-name>
<managed-bean-class>com.pkg.QuizBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
//Older versions of JSF requires this where annotations do not work
//But if you are using JSF 2.0 then it's a lot better to use annotations
You can use more than one beans in a view (page).
If this is an example from Core Java Server Faces, then read more carefully, it explains everything.
msgs as far as I remember, refers to message bundle, declared in faces-config.xml.
As for your question how commandButton knows which bean to call. In your example, the class name QuizBean, most likely correspond to the bean with the same name. That's enough for JSF 2.0. However, you could change that name by 2 methods:
1) If you use JSF managed beans, you should go like this:
#ManagedBean(name="quiz")
#ViewScoped
public class QuizBean { }
2) If you use CDI-beans you would do this:
#Named("quiz")
#RequestScoped
public class QuizBean {}
Remember that CDI-beans scope annotations come from package javax.enterprise.context. And JSF scopes are in the javax.faces.bean package. Do not mix them!
Update:
Please refer to page 35 of the book Core Java Server Faces 3rd Edition for more details about your question and do not hurry to ask questions if you don't understand something right away.

What is the JSF behaviour, if you bind the same backing bean property to two input fields in the same form?

Is there a defined behaviour in JSF, if two input fields are bound to the same session scoped Backing Bean property.
Here is my code snippet
<h:form id="myForm">
<h:inputText id="field1" value="#{TheBackingBean.theProperty}" />
<h:inputText id="field2" value="#{TheBackingBean.theProperty}" />
<h:commandButton id="continueButton" action="#{TheBackingBean.doSomething}" />
</h:form>
My question: If field1 and field2 receive different values, what will be bound to the backing bean property? Is this even allowed?
I know this is a crude scenario. My motivation is, that we have htmlunit tests running for our application. In our JSF application we want to use a cool ajaxified custom component. This doesnt work together very well with htmlunit. So my idea was, I just put in a hidden field that binds to the same property. The unit test then fills the hidden field instead of the "real" thing.
Regards
I think this kind of code is allowed, but I am not sure of the value of theProperty after the submission. What I think is that JSF will do the following:
TheBackingBean.setTheProperty(field1.value);
TheBackingBean.setTheProperty(field2.value);
However, nothing - as far as I know - specifies the order of the setter calls. Thus, after the update values JSF phase, you will not be sure if theProperty will be equal to field1.value or field2.value.
Concerning your scenario, you say that you want to bind the same property to an inputText and an hiddenText. As the hiddenText will not submit its value, unlike the inputText, this problem will not occur. Indeed, if you have this kind of JSF code:
<h:inputText id="field1" value="#{TheBackingBean.theProperty}"/>
<h:inputHidden id="field2" value="#{TheBackingBean.theProperty}"/>
then JSF will only do:
TheBackingBean.setTheProperty(field1.value);
during the submission phase.

Resources