Concatenating strings within EL expression defined in an attribute of a facelets tag
Asked Answered
D

3

39

I need to write an EL expression for an attribute which goes something like this:

#{cc.attrs.appreciatedByCurrentUser ? (cc.attrs.count +'<br/>'+ (cc.attrs.count-1)) : ((cc.attrs.count+1) +'<br/>'+ cc.attrs.count)}

Now the problem is that this gives an error as strings cannot be concatenated, the way I am doing it. So how can I rectify this?

I'm using JSF 2.0 with facelets.


EDIT :

I'm resolving the issue using the following inline javascript

            <script type="text/javascript">
                var count=#{cc.attrs.count};
                document.write(#{cc.attrs.appreciatedByCurrentUser} ? (count-1) +'<br/>'+count  : count+'<br/>'+ (count+1));
            </script>

Can you think of any issue with this?

Dosia answered 12/9, 2011 at 9:59 Comment(0)
S
40

String concatenation in EL is only possible by just inlining in the expression. The + operator is in EL exclusively a sum operator. Further, < and > are invalid characters in XML attributes, so you have to escape them (and instruct <h:outputText> to not escape them once again by escape="false"):

<h:outputText value="#{cc.attrs.count}&lt;br/&gt;#{cc.attrs.count-1}" escape="false" rendered="#{cc.attrs.appreciatedByCurrentUser}" />
<h:outputText value="#{cc.attrs.count+1}&lt;br/&gt;#{cc.attrs.count}" escape="false" rendered="#{!cc.attrs.appreciatedByCurrentUser}" />

Alternatively, you can also use <c:set> to alias the expression:

<c:set var="appreciated" value="#{cc.attrs.count}&lt;br/&gt;#{cc.attrs.count-1}" />
<c:set var="notAppreciated" value="#{cc.attrs.count+1}&lt;br/&gt;#{cc.attrs.count}" />
<h:outputText value="#{cc.attrs.appreciatedByCurrentUser ? appreciated : notAppreciated}" escape="false" />
Ster answered 12/9, 2011 at 12:33 Comment(6)
i had this idea in mind but I saw in another answer by you where you had talked about the performance issues associated with rendered attribute(1 ms for each rendered) If I implement this using your proposed solution that would add up atleast 50 more rendered attributes in my page. Thus 50ms delay..!??Dosia
For pure output components that's really negligible. Anyway, I added an alternative using ui:param. With your JavaScript approach, you're only moving the CPU time from server to client side.Ster
yes, javascript approach doesnt benefit in terms of performance but I just wanted to know(thinking a bit in JavaScript direction), is there any harm from this inline javascript usage., though I like your solution using ui:paramDosia
With ui:param it was possible to use concatenated string as key for resource bundle. Anyway, isn't EL pronounciated by Americans as ILL? I don't think it's an accident ;)Gallery
I like the ui:param suggestion. I never had a need for that element until now.Badmouth
Just appending them in ui:param works for me: <ui:param name="appreciated" value="#{cc.attrs.count} #{cc.attrs.count-1}" />. I'm with Mojarra 2.1.26.Cranage
D
69

It is possible to concatenate Strings in EL using the java.lang.String.concat(String) method. Thus your code could look like:

<h:outputText value="#{cc.attrs.appreciatedByCurrentUser ?  (''.concat(cc.attrs.count).concat('&lt;br/&gt;').concat(cc.attrs.count-1)) :  (''.concat((cc.attrs.count+1)).concat('&lt;br/&gt;').concat(cc.attrs.count))}" escape="false" />

In this particular case however I would go with one of the options that Mr BalusC had suggested because the code above doesn't look quite elegant. In some cases knowing this technique could be useful, though.

I would hardly recommend using javascript as a workaround here.

Dinge answered 9/11, 2012 at 23:45 Comment(3)
Note that this requires EL 2.2.Ster
@Fritz: EL is not part of JSF. It's part of the server. You can even use JSF 1.x on EL 2.2.Ster
I see, @Ster how can you check if a certain server uses which EL? I'm using Websphere 8.5, Java EE 6Exhalation
S
40

String concatenation in EL is only possible by just inlining in the expression. The + operator is in EL exclusively a sum operator. Further, < and > are invalid characters in XML attributes, so you have to escape them (and instruct <h:outputText> to not escape them once again by escape="false"):

<h:outputText value="#{cc.attrs.count}&lt;br/&gt;#{cc.attrs.count-1}" escape="false" rendered="#{cc.attrs.appreciatedByCurrentUser}" />
<h:outputText value="#{cc.attrs.count+1}&lt;br/&gt;#{cc.attrs.count}" escape="false" rendered="#{!cc.attrs.appreciatedByCurrentUser}" />

Alternatively, you can also use <c:set> to alias the expression:

<c:set var="appreciated" value="#{cc.attrs.count}&lt;br/&gt;#{cc.attrs.count-1}" />
<c:set var="notAppreciated" value="#{cc.attrs.count+1}&lt;br/&gt;#{cc.attrs.count}" />
<h:outputText value="#{cc.attrs.appreciatedByCurrentUser ? appreciated : notAppreciated}" escape="false" />
Ster answered 12/9, 2011 at 12:33 Comment(6)
i had this idea in mind but I saw in another answer by you where you had talked about the performance issues associated with rendered attribute(1 ms for each rendered) If I implement this using your proposed solution that would add up atleast 50 more rendered attributes in my page. Thus 50ms delay..!??Dosia
For pure output components that's really negligible. Anyway, I added an alternative using ui:param. With your JavaScript approach, you're only moving the CPU time from server to client side.Ster
yes, javascript approach doesnt benefit in terms of performance but I just wanted to know(thinking a bit in JavaScript direction), is there any harm from this inline javascript usage., though I like your solution using ui:paramDosia
With ui:param it was possible to use concatenated string as key for resource bundle. Anyway, isn't EL pronounciated by Americans as ILL? I don't think it's an accident ;)Gallery
I like the ui:param suggestion. I never had a need for that element until now.Badmouth
Just appending them in ui:param works for me: <ui:param name="appreciated" value="#{cc.attrs.count} #{cc.attrs.count-1}" />. I'm with Mojarra 2.1.26.Cranage
D
1

This is the only thing i can come up with.

<h:panelGroup rendered="#{cc.attrs.appreciatedByCurrentUser}">
   <h:outputText value="#{(cc.attrs.count)}" style="display:block;" />
   <h:outputText value="#{(cc.attrs.count-1)}" />
</h:panelGroup>
<h:panelGroup rendered="#{not cc.attrs.appreciatedByCurrentUser}">
   <h:outputText value="#{(cc.attrs.count+1)}" style="display:block;" />
   <h:outputText value="#{(cc.attrs.count)}" />
</h:panelGroup>

Putting <br> in a value attribute will always throw errors in JSF, so you'll have to use display:block.

Denison answered 12/9, 2011 at 12:19 Comment(1)
Or you could add xmlns="http://www.w3.org/1999/xhtml" and write <h:outputText /><br /><h:outputText />Denison

© 2022 - 2024 — McMap. All rights reserved.