Passing EL method expression as attribute of custom Facelets tagfile - jsf

I created a custom JSF tag:
<ui:composition>
<h:panelGroup>
<rich:dataScroller id="#{id}" for="#{table}" execute="#{table}"
page="#{scrollerPage}" render="#{table}-sc1" maxPages="5"
fastControls="hide" oncomplete="#{onCompl}" scrollListener="#{scrollListenerBean[scrollListenerMethod]}" />
<h:inputText value="#{scrollerPage}" id="#{table}-sc1" size="2">
<f:convertNumber integerOnly="true" />
</h:inputText>
<h:outputText styleClass="outputText"
value=" of #{scrollPagesCount} " />
<h:commandButton value="GO! " />
</h:panelGroup>
</ui:composition>
To pass the listener method, I used the solution suggested in a quite old blog:
<my:dataScroller id="idDS1" table="table1"
scrollerPage="#{bean.navigationHelper.scrollerPage}"
scrollPagesCount="#{bean.navigationHelper.scrollPagesCount}"
onCompl="initForm();"
scrollListenerBean="#{bean}"
scrollListenerMethod="aMethod" />
My questions are: is this the best way to do this? How can I make the method optional?
Thanks a lot for any Help! bye!

My questions are: is this the best way to do this?
That's the only way anyway, provided that you can only use standard JSF/EL facilities and you cannot create a custom taghandler.
You could however create a custom taghandler to convert the value expression to a method expression. The OmniFaces JSF utility library has a <o:methodParam> for exactly this purpose. See also the <o:methodParam> demo page.
You could then end up like:
<my:dataScroller ... scrollListener="#{bean.aMethod}" />
and
<o:methodParam name="scrollListenerMethod" value="#{scrollListener}" />
<rich:dataScroller ... scrollListener="#{scrollListenerMethod}" />
See also:
Dynamic ui include and commandButton
How can I make the method optional?
Theoretically, you could use JSTL tags to build the view conditionally. Something like:
<h:someComponent>
<c:if test="#{not empty fooAttribute}">
<f:attribute name="foo" value="#{fooAttriubte}" />
</c:if>
</h:someComponent>
But that's in the particular case of a special method expression listener attribute unfortunately not possible. There's no such thing as <rich:scrollListener> or something which allows you binding a RichFaces specific scrollListener as a separate tag to the <rich:dataScroller>. Best what you could do without creating custom taghandlers is duplicating the whole <rich:dataScroller> in two <c:if>s (or a <c:choose>); one with and other without scrollListener. This is too clumsy. You'd really better create a custom <my:richScrollListener> taghandler for this which you could then place in a <c:if>.

Related

Passing dynamic param through bundle.properties to alt text value of graphicImage [duplicate]

I have use case in which I have to use resource bundle to display various texts on UI. Some of these resource bundle entries take paramets (e.g. {0}), for these I use h:outputFormat but sometimes that isn't enough.
e.g.
someMessage=Display this message with param {0}
in a resource bundle.
To display it on xhtml I normally do:
<h:outputFormat value="#{msg['someMessage']}"><f:param value="#{someBean.value}"/></h:outputFormat>
That works well when it's a simple case, but for more complex use cases it isn't enough. For example if I want the 'title' attribute of a commandLink to use the above resource bundle entry:
<h:commandLink action="logout" title="#{msg['someMessage']}">
<f:param value="#{someBean.value}" />
<h:graphicImage library="images" name="image.png" />
</h:commandLink>
which doesn't work. I also tried:
<h:commandLink action="logout">
<f:attribute name="title">
<h:outputFormat value="#{msg['someMessage']}"><f:param value="#{someBean.value}"/></h:outputFormat>
</f:attribute>
<h:graphicImage library="images" name="image.png" />
</h:commandLink>
which also doesn't work since f:attibute doesn't allow children.
Even if there is a hack to bypass this (e.g. using hover component from primefaces) there are other fields that might require a parameterized message.
Does anyone know of a way to use MessageFormat that takes an argument in a non-value field of a JSF component?
You could create a custom EL function for this with which you can ultimately end up like:
<h:commandLink ... title="#{my:format(msg['someMessage'], someBean.value)}" />
You can use the MessageFormat API to perform the job, exactly as <h:outputFormat> is doing under the covers.
An alternative is to create a custom component which does the same as JSTL's good 'ol <fmt:message> which supports a var attribute to export the formatted message into the EL scope.
<my:outputFormat ... var="linkTitle">
...
</my:outputFormat>
<h:commandLink ... title="#{linkTitle}" />
Update: JSF utility library OmniFaces has #{of:formatX()} functions and a <o:outputFormat> component for the very purpose.

Use c:set inside ui:repeat does not work

I have a JSF 2 application with the following code:
<c:set var="number" value="0" scope="view" />
<ui:repeat value="${items}" var="item" varStatus="itemIndex">
<c:if test="${item.boolProperty == true}">
<c:set var="number" value="${number + 1}" scope="view" />
</c:if>
<h:outputText value="#{item.name}" />: <h:outputText value="#{number}" />
</ui:repeat>
I want to increase the number depending on the property of the item in the loop. However, the condition seems not to work, since the value of number always stays 0. If I remove the condition, the number is incremented only once, or it is always 0 before incrementing, therefore it outputs 1. Could it be possible the number var changes not to affect the number var that is outside the loop? I believe the scope attribute takes care of that.
JSTL tags and JSF components doesn't run in sync as you'd expect from the coding. JSTL tags runs during building of the JSF view, while JSF components runs during rendering of the JSF view. See for a detailed explanation also JSTL in JSF2 Facelets... makes sense?
What you want to achieve is unfortunately not possible with JSF components. The <ui:param> comes close, but it functions merely as an alias for a more complex EL expression, while the <c:set> actually sets something in the desired scope (the view scope which you've there is by the way wrong).
Your best bet is to change the model or wrap the model in another model so that you end up as
<ui:repeat value="${items}" var="item" varStatus="itemIndex">
<h:outputText value="#{item.name}" />: <h:outputText value="#{item.number}" />
</ui:repeat>

Custom data types in Facelets JSF 2 Expression Language

How to display a custom property using facelet expression language?
For example:
<h:outputText value="#{contact.customTypeProperty}" />
where customTypeProperty is of type CustomClass, and I want to display the String returned by its toString()?
That should already be the default behaviour. You don't need to change anything on the given code example, assuming that the toString() method is properly implemented on the CustomClass. However, if it returns HTML, you'd need to add escape="false" to the output text to prevent JSF from auto-escaping it (which it does in order to prevent XSS attacks on user-controlled input):
<h:outputText value="#{contact.customTypeProperty}" escape="false" />
This is however not necessarily the best practice. You should control the presentation in the view side, not in a toString() in the model side. For example, assuming that CustomClass has in turn two properties foo and bar and you'd like to present it in a table:
<h:panelGrid columns="2">
<h:outputText value="Foo" />
<h:outputText value="#{contact.customTypeProperty.foo}" />
<h:outputText value="Bar" />
<h:outputText value="#{contact.customTypeProperty.bar}" />
</h:panelGrid>
If you did this to avoid code repetition, then you should actually be using an include file or a tag file. See also When to use <ui:include>, tag files, composite components and/or custom components?

Reuse variable outside of composition - passing variables up in jsf?

I'm using jsf 1.2 and have got some weird javascript which gets repeated at several places in my project.
I do not want to repeat myself.. but i found no way to do something similar to this:
<ui:composition>
<c:set var="confirmBlockJS" value="if (confirm('#{tk:encodeJS(confirmMessage)}')) {#{confirmed}} else{ #{notConfirmed}}"/>
</ui:composition>
Now i want to use the set variable but obv this will fail.
<ui:include src="/blocks/tech/confirmBlock.xhtml">
<ui:param name="confirmMessage" value="#{appTexts['action.logout.title']}"/>
<ui:param name="confirmed" value="return false;"/>
<ui:param name="notConfirmed" value=" #{doJS}"/>
</ui:include>
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick='#{confirmBlockJS};'
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
confirmBlockJS is obviously empty at that point, which is actually in my eyes a good thing. But is there no way to pass the variable up? I tried ui:param without luck.
SOLUTION
Use ui:decorate when you want to access variable set with c:set outside of the page which uses the ui:decorate. It will still be visible. In the case of ui:include the c:set will not be visible outside, but ui:param should pass it up (e.g. use ui:param instead of c:set in the ui:include composition)
If you didn't want to inline it as an attribute value, then <ui:decorate> would be the solution for you.
An EL function is closest what you can get to work for this particular functional requirement:
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick="#{js:confirmBlock(appTexts['action.logout.title'], 'return false;', doJS)}"
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
or:
<ui:param name="confirmBlock" value="#{js:confirmBlock(appTexts['action.logout.title'], 'return false;', doJS)}" />
<h:outputLink id="logout" value="#" rendered="#{renderLogout}"
onclick="#{confirmBlock}"
styleClass="_allowEnterKey">
<h:outputText value="#{appTexts['action.logout']}"></h:outputText>
</h:outputLink>
Note that generating JS code by Java/JSF/EL this way is a bit a smell. Is it really not possible to make it a simple JS function which you put in a .js file and parameterize it with arguments?

JSF calls java.net.URLEncoder.encode() method

Is there a way to call java method in .xhtml?
I just want to be able to call java.net.URLEncoder.encode() method from xhtml file.
Is it possible to do this?
In jsp it was very easy to do
Use <f:param>.
<h:outputLink value="page.jsf">
<f:param name="foo" value="#{bean.foo}" />
<f:param name="bar" value="#{bean.bar}" />
</h:outputLink>
This will end up in page.jsf?foo=encodedFooValue&bar=encodedBarValue.
Note: scriptlets indeed eases writing raw Java code in a view template, but that does still not make it a good practice! Use taglibs/EL whenever possible, else the particular logic simply belongs in a real Java class such as a backing bean constructor or method.

Resources