Use ternary operator in freemarker?

JavaFreemarker

Java Problem Overview


I just want to do something like this:

<a href="${ a? 'a.htm' : 'b.htm'}">

Java Solutions


Solution 1 - Java

If you're using freemarker 2.3.23 or newer, you can use the then built-in:

<a href="${a?then('a.htm','b.html')}" target="${openTarget}">

If you're using an older version of freemarker, you can use instead the string built-in:

<a href="${a?string('a.htm','b.html')}" target="${openTarget}">

When applied to a boolean, the string built-in will act as a ternary operator.


Solution 2 - Java

If you are using older Freemarker versions before 2.3.23, then you can use this macro which provides a straightforward way to do ternary operations:

<#macro if if then else=""><#if if>${then}<#else>${else}</#if></#macro>

It's easy to use, looks nice and quite readable:

<@if someBoolean "yes" "no"/>

Note that it is @if - and not #if as in the built-in directive. Here are some more examples.

<!-- `else` is optional -->
<@if someBoolean "someBoolean is true"/>  

<!-- expressions -->
<@if (someBoolean||otherBoolean)  "hello,"+user.name  1+2+3 />  

<!-- with parameter names -->
<@if someBoolean then="yes" else="no" />  

<!-- first in list? -->
<#list seq as x>
    <@if (x_index==0)  "first"  "not first"/> 
<#list> 

For some reason you can't add parenthesis around nameless parameters, if they are non-boolean expressions. That could have increased readability even more.

Solution 3 - Java

You can define a custom function if that is declared like so:

<#function if cond then else="">
  <#if cond>
    <#return then>
  <#else>
    <#return else>
  </#if>
</#function>

The function can be used in any ${...} expression. Your code would look like so:

<a href="${if(a, 'a.htm', 'b.htm')}">

In contrast to @kapep, I think you should use a function, not a macro. Macros produce (textual) output, while functions return a value that can for example be assigned to a variable, but also written to the output, so using a function is more flexible. Furthermore, the way to apply the function is much closer to using a ternary operator, which would also be used inside ${...} expressions, not as a directive.

For example, if you need the conditional link target multiple times, it would make sense to assign it to a local variable:

<#assign targetUrl=if(a, 'a.htm', 'b.htm')/>
<a href="${targetUrl}">link 1</a>
...
<a href="${targetUrl}">link 2</a>

Using the function instead of the macro, @kapep's examples would look like this:

<!-- `else` is optional -->
${if(someBoolean, "someBoolean is true")}  

<!-- expressions -->
${if(someBoolean||otherBoolean, "hello,"+user.name, 1+2+3)} 

<!-- with parameter names: not possible with functions,
     but also not really helpful -->

<!-- first in list? -->
<#list seq as x>
    ${if(x_index==0, "first", "not first")}
<#list>

Solution 4 - Java

As of FreeMarker 2.3.23 you can write a?then('a.htm', 'b.htm'). The advantage of condition?then(whenTrue, whenFalse) over condition?string(whenTrue, whenFalse) is that it works for non-string whenTrue and whenFalse, and that it only evaluates one of whenTrue and whenFalse expressions (whichever branch is chosen).

Solution 5 - Java

Using Interpolation syntax:

"${(a?has_content)?string('a.htm','b.htm')}"

has_content : can be used to handle STRING (returns FALSE in case of empty string)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJack HuView Question on Stackoverflow
Solution 1 - JavaobourgainView Answer on Stackoverflow
Solution 2 - JavakapexView Answer on Stackoverflow
Solution 3 - JavaYetAnotherFrankView Answer on Stackoverflow
Solution 4 - JavaddekanyView Answer on Stackoverflow
Solution 5 - JavaShreyansh JainView Answer on Stackoverflow