Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bounded generic parameters in Play Framework template

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.

like image 405
Itchy Avatar asked Oct 20 '22 14:10

Itchy


1 Answers

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>
 }
like image 77
millhouse Avatar answered Oct 30 '22 01:10

millhouse