can I pass expressions to JSF 2 passthrough-attributes?
the following code is not working. expression #{country.isoCode} is not evaluated.
<h:selectOneMenu value="#{bean.selectedCountry}" styleClass="selectlist">
<f:selectItems
value="#{bean.countries}" var="country"
itemLabel="#{country.countryName}"
pt:data-icon="flag flag-#{country.isoCode}"/>
</h:selectOneMenu>
I am using namespace
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
and bootstrap-select. attribute "data-icon" is used to show an image. see:
http://silviomoreto.github.io/bootstrap-select/#data-icon
rendered output:
<i class="glyphicon flag flag-"></i>
EL is basically supported/evaluated over all place in a Facelet template. Also outside tags/attributes. Even in HTML comments, where many starters then fall over. So that's not the problem.
Your particular case is, unfortunately, "by design". Before rendering the first <option> element, the <f:selectItems> is is wholly parsed only once and turned into an iterator during which all EL expressions will be evaluated. Then, the component will iterate over it while rendering <option> elements during which all passthrough attributes will be evaluated. However, as the var was already evaluated during creating the iterator, it isn't available anywhere during rendering the passthrough attributes and ultimately evaluates to an empty string.
Fixing that would require quite some changes in standard JSF implementation of <f:selectItems>. I'm not sure if JSF guys would be all ears for that, but you can always try to create an issue.
You can work around this by creating physically multiple <f:selectItem> instances during view build time, with help of <c:forEach>.
<h:selectOneMenu ...>
<c:forEach items="#{bean.countries}" var="country">
<f:selectItem
itemValue="#{country}"
itemLabel="#{country.countryName}"
pt:data-icon="flag flag-#{country.isoCode}" />
</c:forEach>
</h:selectOneMenu>
See also:
JSTL in JSF2 Facelets... makes sense?
Related
I have a dropdown and checkbox in my page and if we select a dropdown then the checkbox has to be disabled. We should not use JavaScript for this. I am new to JSF. Is there a way by using JSF. Any ideas.
Just add a <f:ajax> which executes on change of the dropdown and updates the checkbox whereby its disabled attribute checks if the dropdown's value is not empty.
E.g.:
<h:selectOneMenu value="#{bean.selectedItem}">
<f:selectItems value="#{bean.availableItems}" />
<f:ajax render="checkbox" />
</h:selectOneMenu>
<h:selectBooleanCheckbox id="checkbox" disabled="#{not empty bean.selectedItem}" />
That's basically all.
Please note that this uses under the covers still JavaScript for the job! The only difference is that you don't need to manually write any line of JavaScript code, instead JSF autogenerates the necessary JS code for you.
0 and i need to render some buttons based on condition, i'm getting the condition true but each time i visit the page the button its displaying with additionl buttons,here's my code
<ui:repeat var="r" value="#{sessionScope['restrictpageload']}" varStatus="status">
<ui:repeat var="permission" value="#{restrictPageLoad.isUserHasFeaturePermission(4,'abc')}" varStatus="status2">
<ui:fragment rendered="#{permission.featureCreate eq 'y'}" >
<h:commandButton value="Button1" action="#{bean.method()}"/>
</ui:fragment>
</ui:repeat>
</ui:repeat>
here my first <ui:repeat> gets the values from session and i'll pass as parameter to second and this will return me arraylist and i'm going to render the button based on condition.
I'm getting the values inside but each time i visit page two more button addsup.Please help.
too long for a comment...
3 points:
outer loop declares r and status which are not used in inner loop, so "here my first <ui:repeat> gets the values from session and i'll pass as parameter to second" is false
value="#{sessionScope['restrictpageload']}" is equivalent to value="#{restrictpageload}"
value="#{sessionScope['restrictpageload']}" maybe there's a typo. you mean value="#{sessionScope['restrictPageload']}" (uppercase P)
maybe you want to do something like this:
<ui:repeat var="restriction" value="#{bean.pageRestrictions}">
<ui:repeat var="permission" value="#{bean.userPermissions}">
<ui:fragment rendered="#{restriction == permission}">
<h:commandButton value="Button1" action="#{bean.method}"/>
</ui:fragment>
</ui:repeat>
</ui:repeat>
or better
<ui:repeat var="restriction" value="#{bean.pageRestrictions}">
<ui:fragment rendered="#{bean.userHasFeaturePermission(restriction)}">
<h:commandButton value="Button1" action="#{bean.method}"/>
</ui:fragment>
</ui:repeat>
however if your buttons are duplicating, you are adding something to your loops, maybe in isUserHasFeaturePermission?
UPDATE (comment reply)
read carefully the accepted answer of your linked question:
Your question is meaningless. There is no "passing parameters by " and there is no "passing parameters using ". Your words might make sense in some specific context - but the context is missing.
not related but worth mention, NEVER use c:forEach in JSF pages, unless you know exactly how JSF lifecycle works.
passing parameters in expressions depends on EL (ExpressionLanguage) library version.
you can pass parameters only if you have EL 2.2+. this library is shipped (normally) with the servlet container.
read this answer and linked for a complete explanation.
what's your servlet container? tomcat 6.0, glassfish 3.1?
however, does it throws an Exception?
I want to display <span>Lorem Ipsum</span> if a backing-bean value is NOT empty.
<h:outputText rendered="#{not empty pubController.location}">
<span>Lorem Ipsum</span>
</h:outputText>
The Lorem Ipsum does never display. Apparently, it also doesn't work if I remove the NOT in my condition.
FYI: Before I run the h:outputText, I simply print the boolean statements. It prints exactly what I expect. True for the values which are NOT empty. Also, the rendered-condition works also with an h:form tag as I would expect it. Looks like the h:outputText is inappropriate in this case, is it?
Is there a better approach than using h:outputText for what I want to do?
This can't work because h:outputText doesn't accept child elements as stated in the documentation:
If this element has children, they must be ignored by default.
Implementions may provide a configuration option that allows this
element to render its children.
Trying with the following code should solve your problem:
<h:outputText value="Lorem Ipsum" rendered="#{not empty pubController.location}"/>
Note that you could also do the following:
<h:panelGroup rendered="#{not empty pubController.location}">
<span>Lorem Ipsum</span>
</h:panelGroup>
That would be useful if you need to display a more complicated structure than a simple span element.
This example is from a book on JSF. The excercise is to refactor the following Facelets code while eliminating <c:if> and fn:toUpperCase(). Usage of <c:forEach> is allowed.
#{myBean.numbers} returns String["one","two","three"]
As the book is on JSF and not on Java, I suppose the existing Java-code is not to be touched. But I can't think of another way to do this solely in Facelets.
<c:forEach var="item" items="#{myBean.numbers}">
<c:if test="#{not fn:endsWith(item,'o')}">
#{item}
</c:if>
<c:if test="#{fn:endsWith(item,'o')}">
#{fn:toUpperCase(item)}
</c:if>
</c:forEach>
Only thing I can think of is using a converter that conditionally uses String#toUpperCase() and then I still do not understand why use of <c:forEach> should still be allowed:
<ui:repeat var="item" value="#{myBean.numbers}">
<h:outputText value="#{item}" converter="conditionalConverter"/>
</ui:repeat>
Is there a more "Facelets way" to do this (and still a need to use <c:forEach>)?
UPDATE:
Instead of <c:if> one could still use e.g. <h:outputPanel> and it's rendered-attribute, but there is still no Java-less replacement for fn:toUpperCase().
I am asking for learning purposes only. I suppose the <ui:repeat>-solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?
As to <c:if>, the JSF alternative to JSTL <c:if> is the rendered attribute on any component. For example, <h:panelGroup> or <h:outputText>. Those components doesn't generate additional markup if there are no attribtues specified which should end up in HTML, like id or styleClass, otherwise they generate a <span>.
Here's an example of both:
<h:panelGroup rendered="#{not fn:endsWith(item,'o')}">
#{item}
</h:panelGroup>
<h:outputText value="#{fn:toUpperCase(item)}" rendered="#{fn:endsWith(item,'o')}" />
As to fn:toUpperCase(), JSF has no alternative. I'm not sure why you would need a JSF alternative as it's essentially not a tag, but a simple EL function which is perfectly usable in both JSTL and JSF tags. In any case, you could if necessary throw in CSS text-transform: uppercase. As this takes place entirely client side, your only problem may be the browser support.
<h:outputText value="#{item}" style="text-transform: uppercase" />
(note: this is just an example, the normal practice is to put styles in its own .css file which you load by <h:outputStylesheet>)
<h:outputText value="#{item}" styleClass="uppercased" />
I suppose the -solution with a converter is the cleanest and represents most how JSF is supposed to be used. Do you think so, too?
I'm a big fan of "Use the right tool for the job". Use JSTL tags to conditionally build the JSF component tree. Use JSF components to generate HTML. That's it. See also JSTL in JSF2 Facelets... makes sense?
I'm using Primefaces and MyFaces. I would like to use the selectBooleanButton component, to control visibility of other components within a long and rather complex form.
simplified sample code:
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="#{not empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />
<h:panelGroup id="commentPanel"
style="display:#{empty myBean.comment ? 'none' : 'block'}">
<p:inputTextarea value="{myBean.comment}"/>
</h:panelGroup>
The javascript in the onchange attribute simply toggles the display style from none to block and vice-versa to hide or unhide the panel group. I want/need the components to remain in the view, I do not want to use rendered attributes to remove them completely.
Where I get into trouble is because of the EL construct used in the value attribute of the setBooleanButton component. I do realize that this EL statement is not compatible with the set operation, and this results in an exception.
What I want to be able to do is when the form is loaded, have the initial status of the selectBooleanButton components set to 'on' when the comment property has some existing text it, and 'off' when it is empty. I am looking for a way to work around this that would not require me to create a property in the model for each and every instance where I want to hide the panel, as that would result in dozens and dozens of properties because my real world form is very large with many of these comment sections.
I also posted this question on Primefaces forum, and did not receive any answers there either, so at this time there may not be a great solution to this problem, or at least not one that has been shared. What I ended up doing to work around this is to create two versions of the component, and use the rendered attribute to control which one is used, like this:
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="true" rendered="#{not empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />
<p:selectBooleanButton
onLabel="Comment" offLabel="Comment"
onIcon="ui-icon-check" offIcon="ui-icon-close"
value="false" rendered="#{empty myBean.comment}"
onchange="toggleDisplay(this.checked,'myForm:commentPanel');" />