JSF accessing backing map object - jsf

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>

Related

Turn a facelet tag into composite component

Some time ago, based on one of #BalusC answers (really don't know which one of them) I wrote a facelet tag that is a kind of a button generator, that generates a variable number of buttons disposed side-by-side, each one with some parameters passed through the attributes.
Now I want to turn the facelet tag into a composite component (because on the latter, I have the cc:interface tag, that provides information to others developers who wants to use the custom component).
In the rewriting process I must deal with the actions attributes of the dynamically generated buttons. In the facelet tag approach I don't have to declare them as methods, so I can pass their names as simple strings and process them inside the facelet tag also as simple strings and call the action methods. In the composite component approach it seems that I must pass the methods names as actual methods names (by using the method-signature attribute of cc:attribute). The problem is: as I don't know previously the number of buttons (it generates the buttons dinamically), I'm not able to declare the action methods in the cc:interface section.
A simplified version of my working facelet tag is:
<c:set var="idValues" value="#{fn:split(ids,',')}" />
<c:set var="actionValues" value="#{fn:split(actions,',')}" />
<c:set var="numberOfButtons" value="#{fn:length(idValues)}" />
<h:panelGrid id="#{id}" columns="#{numberOfButtons}">
<c:forEach begin="0" end="#{numberOfButtons-1}" varStatus="i">
<p:commandButton id="#{idValues[i.index]}"
action="#{bean[actionValues[i.index]]}" />
</c:forEach>
</h:panelGrid>
and the facelet tag can be used like this:
<my:button id="idButton"
ids="btnSave,btnCancel"
actions="onSave,onCancel"
bean="#{myBean}" />
[EDIT]
As sugested by #BalusC in the answers, adding code like below in the taglib.xml file was enough for the Eclipse autocompletion to work fine:
<tag>
<tag-name>button</tag-name>
<source>tags/bottons.xhtml</source>
<attribute><name>id</name></attribute>
<attribute><name>ids</name></attribute>
<attribute><name>actions</name></attribute>
<attribute><name>bean</name></attribute>
</tag>

Accessing JSF nested composite component elements in JavaScript

I am trying to DRY up popup windows in my JSF 2 project using composite components.
This code base uses Icefaces 3.3.0 (with their 1.8.2 compatibility layer for historical reasons), Mojarra 2.2.7, and Glassfish 4.1.
I have input.xhtml which provides a text input and uses a 2-button popup (ok/cancel), which in turn builds on the basic popup.
input.xhtml:
<composite:interface>
<!-- ... -->
<composite:editableValueHolder name="forInput" targets="theInput"/>
</composite:interface>
<composite:implementation>
<my:popup2Buttons>
<ice:inputText id="theInput" value="..."/>
<script>setInputFocus("#{cc.clientId}:theInput");</script>
</my:popup2Buttons>
</composite:implementation>
popup2buttons.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<my:popup>
<composite:insertChildren/>
<ice:commandButton id="OkButton"
value="Ok"
actionListener="..."/>
<ice:commandButton id="CancelButton"
value="Cancel"
actionListener="..."/>
</my:popup>
</composite:implementation>
popup.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<script>
function setInputFocus(id) {
document.getElementById(id).focus();
}
</script>
<ice:panelPopup>
<f:facet name="body">
<h:panelGroup>
<composite:insertChildren/>
</h:panelGroup>
</f:facet>
</ice:panelPopup>
</composite:implementation>
The popup works mostly as expected, i.e., I can enter something, the ok and cancel buttons work, and validation works as well.
What does not work is my JavaScript code that tries to focus the input when the popup opens.
When I look at the page in Firebug, I see that the input's ID is MyForm:j_idt63:j_idt64:j_idt67:theInput, but the JavaScript code tries to focus an element with the ID MyForm:j_idt63:theInput.
Why is #{cc.clientId} in input.xhtml not the correct ID that the input ends up getting later? What do I need to do to make this work?
I've seen BalusC's hint on adding a binding but I don't want a binding so that the composite component can be independent of any backing beans.
Is there something else I am missing here?
Composite components are implicitly naming containers. I.e. they prepend their ID to the client ID of the children. This makes it possible to use multiple of them in the same view without their children causing duplicate IDs in generated HTML output.
In your specific case, you wrapped the input field in another composite which is in turn wrapped in again another composite. If you're absolutely positive that you don't need multiple naming containers wrapping in each other in this specific composition, then those (popup2buttons.xhtml and popup.xhtml) probably shouldn't be composites, but rather <ui:decorate> templates or <ui:composition> tagfiles. See also When to use <ui:include>, tag files, composite components and/or custom components?
Coming back to the technical problem, it's caused because the #{cc.clientId} does not refer the ID of the nested composite component, but of the current composite component. And thus this would be off. As to the potential solution with binding, the answer which you found does nowhere tell that you should use a backing bean for this. The binding="#{foo}" code in the answer was as-is. It really works that way, without a bean property, see also JSF component binding without bean property. However, this construct would indeed fail when you include the same composite multiple times in the same view and thus multiple components share the same binding="#{foo}". It indeed isn't supposed to be shared by multiple components, see also What is component binding in JSF? When it is preferred to be used?
To solve this without a backing bean, you can use a so-called backing component.
com.example.InputComposite
#FacesComponent("inputComposite")
public class InputComposite extends UINamingContainer {
private UIInput input;
// +getter+setter.
}
input.xhtml
<cc:interface componentType="inputComposite">
...
</cc:interface>
<cc:implementation>
...
<h:inputText binding="#{cc.input}" ... />
<script>setInputFocus("#{cc.input.clientId}");</script>
...
</cc:implementation>
The alternative is to rework them into templates or tagfiles. Be careful that you don't overvalue/overuse composites.

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

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.

Passing valueChangeListener method expression into tag file

I have a <h:inputText> with an event listener like following:
<h:inputText valueChangeListener="#{myBean.handle}"/>
I would like to put it in a tag file which is to be used as follows:
<my:itext changeListener="#{myBean.handle}" />
With inside the tag file:
<h:inputText valueChangeListener="#{changeListener}" />
However it's evaluating it as a property instead of as a listener method. How can I pass the listener method into a tag file?
You can by design not pass method expressions as a tag file attribute. You basically need to convert the ValueExpression to a MethodExpression inside the tag file.
For JSF 2.x Facelets, this can be solved using OmniFaces <o:methodParam>.
<o:methodParam name="changeListenerMethod" value="#{changeListener}" />
<h:inputText valueChangeListener="#{changeListenerMethod}" />
However, for old and deprecated Facelets 1.x or JSP 2.x there is no existing solution. The OmniFaces <o:methodParam> is however open source, you should be able to copy and alter it for Facelets 1.x or JSP if necessary.
Note that when you're actually already using JSF 2.x, you could also use a composite component instead. This supports passing method expressions as <cc:attribute method-signature>. For JSF 1.x you can alternatively also create a real custom component, but that's a bit more work than just some XML.

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.

Resources