How can I use bounded generic parameters in a Scala template within a Play Framework 2.3 Java project?
I currently have something like:
@(entities: List[_ <: Entity], currentEntity: Entity)
<ul>
@for(entity <- entities) {
@if(currentEntity.equals(entity)) {
<li><strong>@entity</strong></li>
} else {
<li>@entity</li>
}
}
</ul>
However, I can call this with different types of entities in entities
and currentEntity
- which is not nice. I would like to do something like:
@[T <: Entity](entities: List[T], currentEntity: T)
...
But this gives me Invalid '@' symbol
as a compile error.
As @m-z points out, it's not supported (yet). But you might be able to get the type-safety you desire (at the cost of another family of classes) by marshalling your arguments into a View object first:
case class HighlightedListView[E <: Entity](entities:List[E], currentEntity:E)
Now in your controller, load up a new HighlightedListView
instance instead of feeding the parameters straight to the template:
def foo = Action {
...
// Assuming some SubEntity exists, the compiler will enforce the typing:
val hlv = HighlightedListView[SubEntity](entities, currentEntity)
Ok(html.mytemplate(hlv))
}
As the comment states, the compiler will barf if your types don't line up. Then the template can be pretty loose with types, because we know we're safe:
@(hlv:HighlightedListView[_])
<ul>
@for(entity <- hlv.entities) {
@if(hlv.currentEntity.equals(entity)) {
<li><strong>@entity</strong></li>
} else {
<li>@entity</li>
}
}
</ul>
You can even take advantage of your new View
object to add helper methods, which can make for easier-to-read templates, and facilitate unit testing:
case class HighlightedListView[E <: Entity](entities:List[E], currentEntity:E) {
def shouldHighlight(e:Any):Boolean = currentEntity.equals(e)
}
leading to:
@if(hlv.shouldHighlight(entity)) {
<li><strong>@entity</strong></li>
} else {
<li>@entity</li>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With