switch, on, case, default, break

Synopsis

Recommended form (on-based), but this is only supported since FreeMarker 2.3.34:

<#switch value>
  <#on refValue1>
    ... (Handles refValue1)
  <#on refValue2, refValue3>
    ... (Handles both refValue2 and refValue3))
  ...
  <#case refValueN>
    ...
    <#break>
  <#default>
    ...
</#switch>

Deprecated legacy form (case-based):

<#switch value>
  <#case refValue1>
    ... (Handles refValue1)
    <#break>
  <#case refValue2>
  <#case refValue3>
    ... (Handles both refValue2 and refValue3)
    <#break>
  ...
  <#case refValueN>
    ...
    <#break>
  <#default>
    ...
</#switch>

Where:

  • value, refValue1, etc.: Expressions evaluates to scalars of the same type.

Additional rules:

  • A switch block either have on-s, or case-s, but not both.

  • default: Optional, can occur at most once. Must be after the on-s. There's no ordering restriction when used with case-s.

  • break:

    • If the switch uses case then break immediately exits from the closes enclosing switch. This is used to prevent fall-through into the next case, or into the following (adjacent) default. (To be precise, break behaves as described if the switch doesn't contain on, and thus also if all it contains is a default.)

    • If the switch uses on then break is not supported by switch directly, but naturally can be used when the switch is inside something else that supports break (like inside a list).

    • With case, continue does the same as break. This is an old bug that works for backward compatibility, but don't utilize it. With on, this is fixed.

Description

Note:

Using this directive with case is not recommended, as it's error-prone because of the fall-through behavior. Starting from FreeMarker 2.3.34, use on instead of case. In earlier versions use elseif-s instead.

Switch is used to choose a fragment of template depending on the value of an expression, and is a shorthand instead using if-elseif-else:

Template
<#switch animal.size>
  <#on "small">
     Processed if animal.size was "small" 
  <#on "medium">
     Processed if animal.size was "medium" 
  <#on "large", "extra large">
     Processed if animal.size was "large" or "extra large"
  <#default>
     Processed if animal.size is neither of the above
</#switch>

Before FreeMarker 2.3.24, on wasn't supported, only case (note the usage of break, and the intentional omission of it after <#case "large">):

Template
<#switch animal.size>
  <#case "small">
     Processed if animal.size was "small" 
     <#break>
  <#case "medium">
     Processed if animal.size was "medium" 
     <#break>
  <#case "large">
  <#case "extra large">
     Processed if animal.size was "large" or "extra large"
     <#break>
  <#default>
     Processed if animal.size is neither of the above
</#switch>

Above examples are basically equivalent with this:

Template
<#assign value = animal.size>
<#if value == "small">
   Processed if animal.size was "small" 
<#elseif value == "medium">
   Processed if animal.size was "medium" 
<#elseif value == "large" || value == "extra large">
   Processed if animal.size was "large" or "extra large"
<#else>
   Processed if animal.size is neither of the above
</#if>

That is, when the switch directive is processed, it chooses an on or case directive where a refValue equals with value, and continues the processing of the template there. If there is no on or case directive with appropriate refValue, then it continues processing at the default directive, if that exists, otherwise it continues the processing after the end-tag of switch.

Be careful with case's fall-through behavior! It means that after processing have jumped on the matching case, it will not leave the switch directive when it reaches another case or default, only when it reaches a break. Example:

Template
<#switch x>
  <#case 1>
    1
  <#case 2>
    2
  <#default>
    d
</#switch>

If x is 1, then it will print 1 2 d (actually with more white-space between); if x is 2 then it will print 2 d; if x is 3 then it will print d. This is usually unintended, or if it is intended then probably not obvious for the reader, and that's why on is recommended over case.