Aug 23, 2012

Ternary Operations in JSTL

An often overlooked operator, in JavaScript (and elsewhere), is the ternary operator. It’s written like this:

condition ? when_true : when_false

It’s a little hard to make out in the mark-up, but the operators are the question-mark and colon, and they act together to give an in-line condition. A boolean expression starts the operation; it can be any expression that will evaluate to “true” or “false.” The question-mark denotes the end of the boolean expression, and what follows is what will be used when the condition is true. The colon denotes the end of the true expression, and what follows is what will be used when the condition is false.

In a long form, it can be seen as this action:

if( condition ) {
  when_true
} else {
  when_false
}

Generally this is used to set values. The “when true” and “when false” are typically simple expressions. They can’t be too complex in that they can really only be one operation. That is to say, it can only be “one line” or “one statement” of action. That one statement might be a string of function calls (as in someInstance.member().nestedMember().anotherMember() and so on). Further, both results need to “return” the same “type.” That means that you should be able to assign the results of the true and false portions to the same variable; oh, and that neither can be “void.” An operation like the following might not be valid unless autoboxing or other scalar interpretation is done, or the type is generously accepting, such as “Object”:

something = whatever ? 5 : 'five'

Understanding ternary operators is helpful. Using them correctly and frequently is a lot more helpful.

For this particular discussion, take an example that is seen far too often in JSP:

<c:choose>
 <c:when test="${something}">
  <div class="when_something">
 </c:when>
 <c:otherwise>
  <div class="not_something">
 </c:otherwise>
</c:choose>
Div content here.</div>

While perfectly valid JSP, it will confuse many JSP validators as it can appear to be the case that the <div> opened inside the <c:when> and <c:otherwise> aren’t closed, and the </div> after the content isn’t opened. This is because many validators can’t handle the conditional nature of “really only one of those is going to be written.” In the XML-like nature of the JSP mark-up, it should be the case that everything in the tags contains complete and closed mark-up, so those validators are right to complain.

Further, we’re one mistake away from “maybe one of those isn’t going to be written”; if that <c:otherwise> wasn’t there, a series of <c:when> could result in a case where none of them matched. If it were rewritten to use a series of <c:if> instead, it could be the case that none or more than one of them matched.

Using a ternary operator in these cases can streamline the JSP, satisfy the validators, and reduce the risk of ending up with invalid HTML. Consider this smaller JSP:

<div class="${something ? 'when_something' : 'not_something'}">
Div content here.</div>

This much cleaner use with the ternary operator results in the same class declarations in our <div> without confusing validators or potentially breaking the HTML. We know there will always be an opening <div>, and there will only be one, and the class will be properly set.

Nesting ternary operators allows for more than two conditions, but beware a pitfall of trying to nest too deeply. Consider this three-case condition, where we might need to set apart zero, one, or other values:

<div class="${something == 0 ? 'zero_something' : something == 1 ? 'one_something' : 'other_something'}'>
Div content here.</div>

Nesting like this results in long ternary operations, and can get confusing for human readers, and for some parsers if poorly written. In this case it might be better to figure out the value in advance using a <c:choose> or series of <c:if> in our JSP, or setting the value before the JSP in a Servlet or Filter.

For completeness, here’s that last example in a longer form that still meets our condition of always valid HTML with just one <div> opening, and the right class definition:

<c:set var="className" value="other_something"/>
<c:if test="${something == 0}"><c:set var="className" value="zero_something"/></c:if>
<c:if test="${something == 1}"><c:set var="className" value="one_something"/></c:if>
<div class="${className}">
Div content here.</div>

A similar solution could have been used for our initial example, too, if you’re really not into ternary operators.

About the Author

Object Partners profile.
Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
An Exploration in Rust: Musings From a Java/C++ Developer
Why Rust? It’s fast (runtime performance) It’s small (binary size) It’s safe (no memory leaks) It’s modern (build system, language features, etc) When Is It Worth It? Embedded systems (where it is implied that interpreted […]
Getting Started with CSS Container Queries
For as long as I’ve been working full-time on the front-end, I’ve heard about the promise of container queries and their potential to solve the majority of our responsive web design needs. And, for as […]
Simple improvements to making decisions in teams
Software development teams need to make a lot of decisions. Functional requirements, non-functional requirements, user experience, API contracts, tech stack, architecture, database schemas, cloud providers, deployment strategy, test strategy, security, and the list goes on. […]
JavaScript Bundle Optimization – Polyfills
If you are lucky enough to only support a small subset of browsers (for example, you are targeting a controlled set of users), feel free to move along. However, if your website is open to […]