This issue looks for the posibilities of if and if-else structures, and sums up a number of usages.
Not sure if this is better suited as a wiki, but in some approaches, new classes are needed.
Often a tag has to be placed under a condition. For example, if the current page number is equal to the value i than use a span tag, otherwise an anchor tag. There are multiple ways to perform conditional logic in j2html, and maybe some undiscovered ones that could improve the api.
Examples with an if-else-structure:
Example with condWith():
ul().with(
li().condWith(pageNumber == currentPageNumber,
span(pageNumber + "")
).condWith(pageNumber != currentPageNumber,
a(pageNumber + "").withHref("http....")
)
);
Example with the ternary operator:
ul().with(
li().with(pageNumber == currentPageNumber
? span(pageNumber + "")
: a(pageNumber + "").withHref("http....")
)
);
The ternary operator example is cleaner in this case because the condition only has to be specified once, and no additional with() or condWith() is required, and also no parent tag is required. Also, the ternary operator only executes/evaluates one its bodies, while conWith always execute the body, even if the condition fails.
But in case only an if-structure is needed instead of an if-else, something new has to be introduced when a ternary operator is used.
Examples with an if-structure:
Example with condWith():
ul().with(
li().with(
div("Message " + message.getContent())
).condWith(message.getUser().equals(currentUser),
a("delete").withHref("http....")
)
);
The drawback of this approach may be the use of both with() and condWith().
Example with ternary operator, with a new introduced class/method:
ul().with(
li().with(
div("Message " + message.getContent()),
message.getUser().equals(currentUser)
? a("delete").withHref("http....")
: none
)
);
Which may feel a bit cleaner, although the message.getUser().equals(currentUser)
line may not immediately appear/suggest that it is a condition, and none
may be a bit verbose. "none" is used in Python and Scala to indicate nothing, although an empty group() of something like an invisible parent tag without child tags may also be an option. "none" can be be a static field, since only one instance is needed.
Another approach would be to introduce an IF() method. ("if" is a reserved keyword, so I use "IF" in this example, although there may be better names.)
Example with IF():
ul().with(
li().with(
div("Message " + message.getContent()),
IF(message.getUser().equals(currentUser),
a("delete").withHref("http....")
)
)
);
Although a drawback of IF (and also for condWith) is that the code is evaluated even if the condition fails, which can lead to NullPointerExceptions:
IF(message.getUser() != null,
span("User: " + message.getUser().getName()) // still executes if the condition fails
)
For this null problem, the Java 8 Optional class/monads may be used. Example with Optional class:
ul().with(
li().with(
Optional.of(message.getUser()).filter(u -> u.equals(currentUser)).map(
a -> span(a)
).orElseGet(none);
)
);
Optional can also be used with if-else structures:
ul().with(
li().with(Optional.of(pageNumber).filter(p -> p == currentPageNumber).map(p ->
span(p + ""))
.orElseGet(() ->
a(pageNumber + "").withHref("http....")
)
)
);
The advantage of using Optional/monads is that it only evaluates the code when required, and also gives the flexibility to define code (a lambda bodies), although the code is verbose.
My preference: (under change)
Not sure yet what my prefered solution would be. Mixing condWith for if-structures with the ternary operator for if-else-structures feel a bit inconsistent. So then I would probably lean to using the ternary operator with the non-existing none static field.
When I need more safety or when optional if/if-else bodies are expensive, of when more flexibility is needed, I would probably lean to the more verbose Optional/monad approach.