Passing valueChangeListener method expression into tag file - jsf

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.

Related

How to set HTML5 data attribute in JSF? [duplicate]

I want to add some iOS specific tag attributes to my login-form. If I have a look on my web page source, the attributes autocorrect, autocapitalize and spellcheck aren't there. What is the reason for this? I am using JSF 2.x.
<h:inputText id="user-name" forceId="true" value="#{login.username}" style="width:120px;"
autocorrect="off" autocapitalize="off" spellcheck="false" />
This is by design. You can only specify attributes which are supported by the JSF component itself (i.e. it's listed in the attribute list in the tag documentation). You can't specify arbitrary additional attributes, they will all be plain ignored.
There are several ways to solve this:
If you're already on JSF 2.2+, simply specify it as passthrough attribute:
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputText ... a:autocorrect="off" />
(note that I'm using xmlns:a instead of xmlns:p to avoid clash with PrimeFaces default namespace)
Or:
<html ... xmlns:f="http://xmlns.jcp.org/jsf/core">
...
<h:inputText ...>
<f:passThroughAttribute name="autocorrect" value="off" />
</h:inputText>
Create a custom renderer. You can find several concrete examples in below answers:
How to let JSF pass through HTML attributes
Using bootstrap related tags inside JSF2 h:inputText component
How to render a custom attribute of <h:outputLink>?
InputText PrimeFaces not applying maxlength
Adding Custom Attributes to Primefaces Autocomplete Component in JSF

pass bean action as attribute in custom tag inside ui:repeat [duplicate]

In my JSF 1.2 project, I have created a facelet tag file and defined an inputText that has actionListener attribute to which I need to pass the backing bean method name.
I tried defining a variable actionListener="#{actionListener}" in the tag file. In my xhtml where I call the component, when I pass the value as
actionListener="#{myBean.preFillData}"
tag file treats it as a property and errors out indicating no property 'preFillData' found. If I change it to
actionListener="#{myBean.preFillData()}"
then there is a parse error in the tag file because it doesnot like parenthesis to indicate method name.
How do we pass method name to the tag file?
Thanks
PT
Passing method expressions is not supported in tag files. Only since JSF 2.0 it's possible with so-called composite components.
What you can do is to separate the bean reference and the method name so that you can use the brace notation to invoke the method. I'm only not sure if that works out for an actionListener, you normally don't use that to invoke actions, but it should definitely work for an action.
E.g.
<my:tag ... bean="#{myBean}" actionMethod="preFillData" />
with inside tag.xhtml
<h:commandButton ... action="#{bean[actionMethod]}" />
Only if you happen to use JSF 2.0 on Facelets, then you can use <o:methodParam> to pass a method expression to a tag file. See also a.o. Dynamic ui include and commandButton.

How to add tooltip to f:selectItems

For example the f:selectItems component doesn't support the title attribute in some versions of JSF.
Would it be possible to replace JSF Components by their plain HTML counterparts using JSFC and do something like this?
<select jsfc="h:selectOneMenu" value="#{cc.data}">
<option jsfc="f:selectItems" value="${cc.listItems}" var="item" title="#{item.tooltip}"></option>
</select>
instead of
<h:selectOneMenu value="#{cc.data}">
<f:selectItems value="#{cc.listItems}" />
</h:selectOneMenu>
Doing exactly so, replacing the latter by the above, I'm getting "<f:converter> Parent not an instance of ValueHolder: javax.faces.component.html.HtmlPanelGroup" Facelet TagExceptions
Would it be possible to replace JSF Components by their plain HTML counterparts using JSFC and do something like this
Nope. Ultimately, such a HTML element with jsfc attribute will be turned into a true JSF component in the JSF component tree and only the attributes supported by the component in question would be parsed and set as component attribute. The title attribute isn't among the supported attributes of UISelectItem component. I'm not sure what exactly you mean with "some versions of JSF". The standard JSF API already doesn't support it in first place. JSF spec issue 529 describes this shortcoming and is currently still open.
If you're using JSF 2.2, make use of passthrough attributes. You only need to replace <f:selectItems> by <c:forEach><f:selectItem>, see also Using f:selectItems var in passtrough attribute
<... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
<c:forEach value="#{bean.items}" var="item">
<f:selectItem itemValue="#{item}" a:title="#{item.tooltip}" />
</c:forEach>
Based on your question history you seem to be not using JSF 2.2 yet. If you can't upgrade, you basically need a custom renderer for <h:selectOneMenu>.
While creating the custom renderer, you could make use of the unused(!) description property of the UISelectItem class. I've answered this before on a similar question targeted at <p:selectManyCheckbox>: Primefaces tooltip for p:selectManyCheckbox or other p:selectMany*/One*.
<f:selectItems ... var="item" itemDescription="#{item.tooltip}" />
Noted should be that creating the custom renderer for <h:selectOneMenu> is a pain, particularly if you intend to be JSF implementation independent. Theoretically, a custom ResponseWriter should be able to catch this, but unfortunately, the <h:selectOneMenu> only passes itself when writing <option>, instead of the UISelectItem in question.
In my case (JSF 2.2 / Mojarra 2.2.14), itemDescription worked out of the box. I.e:
<c:forEach items="#{bean.items}" var="item">
<f:selectItem itemValue="#{item}" itemLabel="#{item}" itemDescription="#{item.tooltip}" />
</c:forEach>

How to implement <f:setPropertyActionListener> programmatically

Basically i'm trying to set a dynamic columns for a <p:datatable>.
The content of one of my columns is a p:commandLink which used to show a dialog for text editing, i have this working like a charm in the XHTML but I need to translate it to Java for dynamic user customization and preferences.
here is what is my XHTML version:
<p:commandLink id="MRepShowButton" update=":form1:display" onclick="EditorDialog.show();" title="Editer le compte rendu">
<f:setPropertyActionListener value="#{exam}" target="#{examenListBean.selectedExamen}" />
</p:commandLink>
and this is my Java version(not working):
CommandLink rapstatelink = (CommandLink)application.createComponent(CommandLink.COMPONENT_TYPE);
rapstatelink.setId("MRepShowButton");
rapstatelink.setUpdate(":form1:display");
rapstatelink.setOnclick("EditorDialog.show();");
rapstatelink.setTitle("Editer le rapport du patient");
ValueExpression target = ef.createValueExpression(elc, "#{exam}", Object.class);
ValueExpression value = ef.createValueExpression(elc, "#{examenListBean.selectedExamen}", Object.class);
//rapstatelink.setActionListener(new SetPropertyActionListenerHandler(**i don't know wht to do here **));
column.getChildren().add(rapstatelink);
table.getChildren().add(column);
You need UICommand#addActionListener(), not UICommand#setActionListener(). The setActionListener() is a deprecated method from JSF 1.x which effectively does a <p:commandLink actionListener="..."> with a ValueBinding.
As to creating the <f:setPropertyActionListener> programmatically, there's unfortunately no JSF implementation independent way for that. Choose either of the following options:
Use the JSF implementation specific class, in case of Mojarra that's the com.sun.faces.taglib.jsf_core.SetPropertyActionListenerImpl:
link.addActionListener(new SetPropertyActionListenerImpl(target, value));
In case of MyFaces that's the org.apache.myfaces.event.SetPropertyActionListener:
link.addActionListener(new SetPropertyActionListener(target, value));
Keep in mind that using JSF implementation specific classes com.sun.faces.* or org.apache.myfaces.* in your own code is a poor practice.
Create a custom ActionListener implementation which does the job. Basically, just copypaste the class' source code from either Mojarra or MyFaces source code into your package. As compared to 1) this has the advantage that your web application does not break when deployed to a Java EE container which ships with the other JSF implementation bundled.
Make use of EL 2.2 feature of the ability to pass method arguments in EL expressions. Then you can just do the job in action or actionListener attribute:
link.setActionExpression(ef.createMethodExpression(elc,
"#{examenListBean.setSelectedExamen(exam)}", Void.class, Exam.class));
(the Exam.class should represent the type of #{exam})
This does effectively the same as
<p:commandLink ... action="#{examenListBean.setSelectedExamen(exam)}" />
Or if you really need to set an action listener:
link.addActionListener(new MethodExpressionActionListener(ef.createMethodExpression(elc,
"#{examenListBean.setSelectedExamen(exam)}", Void.class, Exam.class)));
This does effectively the same as
<p:commandLink ... actionListener="#{examenListBean.setSelectedExamen(exam)}" />

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>

Resources