scalaplayframework-2.0scala-template

Reusable functions between templates in Play Framework templates


In Play Framework inside of a template I can define functions like that:

@title(text: String) = @{
  text.split(' ').map(_.capitalize).mkString(" ")
}

<h1>@title("hello world")</h1>

Can I define such function in separate file and make it reusable between multiple templates?


Solution

  • There are at least several solutions:

    First is using tags as Makis showed you and in most cases it's ok, even if it adds additional empty lines it doesn't matter (at least when we are talking about generating HTML snippets i.e. representing repeating news items on list) - you can i.e. optimize/compress your HTML in post-process if you care about transfer rates.

    Second is creating a Scala object which contains static functions (in Java it's also possible) and returns the play.twirl.api.Html("<div>your code</div>"), this way you can programmatically fit your code exactly as you need, avoid empty lines, remove or replace spaces, etc. Just in your template you will need to use syntax like: @full.qualified.path.to.Object.method("foo", "bar") returning the Html("...") causes that you do not need to escape returned code within your view.

    Third approach is using own TemplateMagic-like methods which allows you to extend objects of any type and perform some logic on it, good sample is "active".when(someCondition) syntax, you can see as it's done in the repo. Of course you need to just create custom class like this and the import it on the beginning of your view(s). Also keep in mind that it doesn't need to be only one Boolean argument, your methods can use as many parameters as you need - any type you need. It can be just parameterless.

    edit - sample:

    app/myapi/MyMagic.scala

    package myapi
    
    import play.twirl.api.Html
    
    import scala.language.implicitConversions
    
    object MyMagic {
    
      class RichString(string: String) {
    
        def upperWords() = {
          Html(string.split(' ').map(_.capitalize).mkString(" "))
        }
    
        def bold() = {
          Html("<b>" + string + "</b>")
        }
    
        def when(predicate: => Boolean) = {
          predicate match {
            case true => string
            case false => ""
          }
        }
    
      }
    
      implicit def richString(string: String): RichString = new RichString(string)
    }
    

    usage in view(s)

    @(title: String)
    @import myapi.MyMagic._
    
    @main("Welcome to Play") {
    
        @title.upperWords() <br>
        @{"foo bar baz".upperWords()} <br>
        @{"I'm bolded LOL".bold()} <br>
    
        <ul>
            @for(item <- 1 to 10){
                <li >Item no.: @{item} @{"(first item)".when(item==1)}</li>
            }
        </ul>    
    }