JSF switching image - jsf

This is a follow-up to question Using <c:when> with an enumeration
After following the suggestion from the accepted answer, I encountered another problem. The real image path (my code was example code) is partially generated using a library function to get a themed image path. Please understand that I'm not allowed to disclose real code, so I have to cut lots of pieces when I post here.
The first problem is that h:graphicImage automatically generates an absolute image path for the img tag using the current portlet's path. Example: I need http://myserver/mytheme/portlet/image.gif but if I use <h:graphicsImage value="#{myNs:getThemePath()}image.gif" /> it gets rendered as http://myserver/myportlet/mytheme/portlet/image.gif; instead, using <img src="#{myNs:getThemePath()}image.gif" /> works perfectly.
As specified in the other question, I need to switch between images basing on a condition of an iterating item in an ICEFaces table, AND I also need (for accessibility reasons) to place a correct alt attribute with a localized resource.
Briefly, my code resembles the following (ice:dataTable omitted)
<h:column>
<f:facet name="header">
<ice:outputText value="#{myNs:getLocale('state')}" />
</f:facet>
<img alt="[[TODO]]" src="#{myNs:getThemePath()}#{item.state == 'COMPLETED' ? 'ok' : 'ko'}.gif"
</h:column>
The src part works, but now come the problems.
If I use alt="#myNs:getLocale('prefix.#{item.state = 'COMPLETED' ? 'completed' : 'canceled'}')} I can't nest expressions (it doesn't get evaluated)
If I create two <h:graphicsImage tags for the two cases (no need to use complex expressions in alt) and use the rendered attribute as described in the other question's accepted answer, I don't get the image URL rendered correctly.
I also can't use the <c:when tag because, as explained in the other question, it gets always evaluated to false.
What can I do to meet both requirements? How can I use two <img tags and switch their rendering according to my condition?
Thanks
[add] Fortunately, I got the following exception message on Tomcat logs when combining expression . Can somebody help me learn EL expressions better? I'm totally new to JSF
Caused by: org.apache.el.parser.ParseException: Encountered "#" at line 1, column 32.
Was expecting one of:
<INTEGER_LITERAL> ...
<FLOATING_POINT_LITERAL> ...
<STRING_LITERAL> ...
"true" ...
"false" ...
"null" ...
"(" ...
"!" ...
"not" ...
"empty" ...
"-" ...
<IDENTIFIER> ...
<FUNCTION_CALL> ...

To answer the concrete question of the ability to render plain vanilla HTML conditionally; just wrap them in a JSF component which supports the rendered attribute but does by itself output nothing.
<h:panelGroup rendered="#{item.state == 'COMPLETED'}">
<img src="ok.gif" />
</h:panelGroup>
<h:panelGroup rendered="#{item.state == 'CANCELLED'}">
<img src="ko.gif" />
</h:panelGroup>
You can also use <ui:fragment> instead when you're using Facelets. It has a bit less overhead.

Looks like I solved it by myself in 10 minutes. Let me share how.
A combined expression is feasible, but simply needs no #{} again!!!! What a dumb (did I say I'm a total beginner?)
#{item.state = 'COMPLETED' ? myNs:getLocale('prefix.completed') myNs:getLocale('prefix.canceled')}
works

Related

Alternative c:if in JSF

Does someone know a alternative to <c:if> for view render time, or even if that is possible. For what I have search until now it doesn't exist, or the alternative would be using the rendered attribute, but for me doesn't really work.
<af:listView value="#{bindings.date.collectionModel}" var="item" id="lv1">
<af:listItem id="li2">
<af:iterator id="i1" value="#{bindings.list.collectionModel}" var="row">
<c:if test="#{item.bindings.attrid.inputValue eq row.attrid}">
<ui:param name="varUI" value="true" />
<c:set var="varC" value="true" />
</c:if>
</af:iterator>
<af:outputText value="#{varUI}" id="otqaswq"/>
<!--<af:outputText value="#{varC}" id="otqawq"/>-->
<af:selectBooleanCheckbox text="Activated" id="sbc2" value="#{varUI}"/>
</af:listItem>
</af:listView>
So in the code above I know that c: they run in different time, view build time and not on the render time.
What I needed was that the af:selectBooleanCheckbox would appear true or false depending if there are values with the same value.
My question is, someone know a alternative way of doing this?
rendered should 100% work, your expression may be incorrect.
Switching to another alternative where you will use exactly the same expression will lead you in the very same place.
You cannot use an <af:iterator> to conditionally set a value using <ui:param> or <c:set>, because they are both tag handlers which are evaluated before <af:iterator>. You might use <c:forEach> instead, but that requires some collection to iterate over. A javax.faces.model.DataModel like #{bindings.list.collectionModel} will most likely not work.
But to be honest, you should implement some Java method which will give you the desired value (true or false) instead of trying to implement this logic in terms of JSF tags.

<a jsf:rendered="#{...}"> is not interpreted as passthrough element

I don't understand why this piece of code is working:
<h:link value="Login" rendered="#{sessionBean.userInSessionBean == null}" />
and this piece of code is not working:
<a jsf:rendered="#{sessionBean.userInSessionBean == null}">Login</a>
A HTML element will only become a passthrough element if following conditions are met:
There's at least one jsf:xxx attribute from http://xmlns.jcp.org/jsf namespace.
There's at least one "identifying attribute" associated with a specific JSF component.
For the <a> element an identifying attribute is necessary so JSF can decide whether to interpret it as <h:commandLink>, <h:outputLink> or <h:link>. Without an identifying attribute, JSF wouldn't have any idea what component you actually meant to use, so any jsf:xxx attributes will be ignored. The jsf:rendered is not sufficient as identifying attribute because it appears on every single JSF component, so JSF would still have no idea which one you meant.
Given that you seem to intend to have a <h:link>, then use jsf:outcome as identifying attribute.
<a jsf:outcome="login" jsf:rendered="#{empty sessionBean.userInSessionBean}">Login</a>
A completely different alternative is to wrap plain HTML in an <ui:fragment rendered>. See also How to conditionally render plain HTML elements like <div>s?

h:outputText need style for particular text

I'm using Primefaces 5.1. In my student I need style particular style in particular text.Below code I try It will show error(The value of attribute "value" must not contain the '<' character). So I replace < to &< and &&gt for > that time I faces error(The entity name must immediately follow the '&' in the entity reference)
<p:outputPanel>
<h:outputText styleClass="noWrap" escape="false"
value="#{common.ConfirmMessage1} <b style='color:red'>'
#{student.numberOfUserFound}'</b>"/>
</p:outputPanel>
My doubt is separate text is solution or any other way?
Just don't use <h:outputText>. It has no technical necessity in this specific case.
<p:outputPanel>
<span class="noWrap">
#{common.ConfirmMessage1}
<b style='color:red'>'#{student.numberOfUserFound}'</b>
</span>
</p:outputPanel>
See also:
Is it suggested to use h:outputText for everything?
That being said, I suggest to take a step back from JSF and start learning some basic HTML first. JSF will then be easier to understand. In the context of this question, JSF is just a HTML code generator.

Seam conditional render without parsing

I'm trying to make a conditional render in my Seam application (2.2.0), to display two different controls depending on a condition.
I'm using the s:fragment tag with the render attribute, but my problem is that I want whatever the control is displayed, to have the same id:
<s:fragment render="${editable}">
<rich:calendar id="entityDate"..../>
</s:fragment>
<s:fragment render="${!editable}">
<h:outputText id="entityDate".../>
</s:fragment>
My problem is that even when the render attribute set to false, the "not to be rendered" element is parsed, and I get an exception because of the duplicated id.
I also tried with the tag <ui:remove>, which effectively removes the element before the parsing phase, so I can have something like:
<span id="myId"/>
<ui:remove>
<span id="myId"/>
</ui:remove>
Unfortunately the <ui:remove> tag doesn't allow conditional logic. Has anyone found a way to solve this?
That's only possible when you use a view build time tag such as JSTL <c:if>.
<c:if test="#{editable}">
<rich:calendar id="entityDate" />
</c:if>
<c:if test="#{!editable}">
<h:outputText id="entityDate" />
</c:if>
(note that this is not going to work within an iterablte JSF component, such as <ui:repeat>, <h:dataTable> and so on)
After all, I strongly recommend to take benefit of the disabled attribute instead, if necessary with a good shot of CSS to hide the input field borders and so on. It'll minimize the JSF view boilerplate code.
<rich:calendar id="entityDate" disabled="#{!editable}" />
Disabled inputs are separately styleable by the CSS attribute selector element[attribute], e.g.
input[disabled] {
border: 0;
}
The above removes the border of input elements with the disabled attribute present so that it look like a normal output text.
"Solve"? There is nothing to solve here: two elements in a GUI can not have the same ID. Hardly unnatural or unsound?
It's like asking: "I have a database table with two rows, I would like them both to have the same primary key value, but somehow I get these errors... has anyone managed to solve the problem and circumvent the constraints?".
Or even closer analogy: "I have two spans, one of them is invisible (has style="display: none") I would like them both to have the same id - and browsers seem not to like it, despite one of the spans being invisible".
Bottom line: rendered on not rendered, each component is still a part of the view tree, and therefore has a UNIQUE id.
I have a suspicion that you want to have some "polymorphic" code that should work with the currently visible element. Using ID for such code IS WRONG. If you show us your use case, we might find a right way to achieve the effect.
I use selenuim myself in a seam environement and i recommend using defined ids whenever possible. First you have the ability to create smaller ids which is usefull for pagesize. Second the selenium test run alot faster if you use ids for referencing instead of other selectors. I have not yet found a selenium test where you cannot handle diffrent ids. Additionally if a code fails in jsf tree creation you see which id is failing.
I see you are using sfragment with editable or not. I use the sdecorate and give the decorate an id and then "just" ed for the input and vi for the outputtext for example. This makes it easy in selenium to check the availability of edit or view components.
Would you be able to get the same results you need by putting the id tag on the fragment?
So:
<s:fragment id="entityDate">
<rich:calendar render="${editable}" />
<h:outputText render="${!editable}" />
</s:fragment>

JSF <h:outputFormat>: use array values as parameters

On my JSF2 page, i'm using internationalized error messages.
In my backing bean, i'm putting the messages into the flash Scope:
flash.put("error", exception.getType());
On the page, this string gets translated this way:
<h:outputText value="#{bundle[flash.error]}"/>
Works fine.
NOW i want to be also able to put (an arbitrary number of) parameters into the message text, that get inserted into the placeholders in the i18n-property in my message.properties. Therefore, i'm putting the parameters as a String array into the Flash Scope, like this:
//exception.getParameters returns String[]
flash.put("errorParams", exception.getParameters())
Now i also want to be able to use this String array as parameters for an outputFormat element, to insert them into a property like Welcome, {0} {1}.
So i tried to achieve this by using ui:repeat:
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<ui:repeat value="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
<!-- also doesn't work: <f:param value="#{_param}"/>-->
</ui:repeat>
</h:outputFormat>
Unfortunately, the param value is ignored and the placeholders of the i18n-property aren't replaced, so the rendered output is Welcome, {0} {1}. When using a "regular" repeater, displaying the array elements just as an outputtext, it works. So the outputFormat tag doesn't seem to support the use of a repeat as a child.
Damn, so close ;) Anyone knows a good way to do what i want, or is there any component library supporting something like that?
The problem here is that ui:repeat is a render-time child of h:outputFormat which it indeed doesn't support at all. You'd like to put multiple f:param elements directly as children of h:outputFormat during build time.
The c:forEach is suitable for this task. The JSTL core tags (which are already included in Facelets, so you don't need to install any extra JARs) do their job during building the view tree, right before it's JSF turn to process/render the view tree.
<html xmlns:c="http://java.sun.com/jsp/jstl/core">
...
<h:outputFormat value="#{bundle[flash.error]}" rendered="#{! empty flash.error}" class="invalid">
<c:forEach items="#{flash.errorParams}" var="_param">
<f:param value="#{bundle[_param]}"/>
</c:forEach>
</h:outputFormat>

Resources