I did something similar in Playscala 2.4, but having the scripts included in the footer, right in front of the body closing tag. I am not familiar with the Play java api, but I believe the concept still works.
Here is the gist: https://gist.github.com/zv3/2dad7cb63813e82f8412
Controllers / StackableAction.scala
// Borrowed from: https://github.com/rabitarochan/Play2-ChainAction/blob/master/core/src/main/scala/com/github/rabitarochan/play2/stackableaction/StackableAction.scala abstract class StackableAction extends ActionBuilder[RequestWithAttributes] with StackableFilter { override def filter[A](request: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result] = { f(request) } def invokeBlock[A](req: Request[A], block: RequestWithAttributes[A] => Future[Result]): Future[Result] = { val reqWA = new RequestWithAttributes(req, new TrieMap[AttributeKey[_], Any]()) filter(reqWA)(block) } } trait StackableFilter { def filter[A](request: RequestWithAttributes[A])(f: RequestWithAttributes[A] => Future[Result]): Future[Result] } trait AttributeKey[A] { def ->(value: A): Attribute[A] = Attribute(this, value) } case class Attribute[A](key: AttributeKey[A], value: A) { def toTuple: (AttributeKey[A], A) = (key, value) } class RequestWithAttributes[A](request: Request[A], attributes: TrieMap[AttributeKey[_], Any]) extends WrappedRequest[A](request) { def get[B](key: AttributeKey[B]): Option[B] = attributes.get(key).asInstanceOf[Option[B]] def set[B](key: AttributeKey[B], value: B): RequestWithAttributes[A] = { attributes.put(key, value) this } def getAll[T](implicit classTag: ClassTag[T]) = { attributes.filterKeys { case p: T => true case _ => false } } }
opinions / support / JavascriptPage.scala
object JavascriptPage { case class NonBlockingJS(key: String) extends AttributeKey[Html] case class BlockingJS(key: String) extends AttributeKey[Html] def addNonBlockingJS(div: String)(jscript: Html)(implicit request: Request[_]): Unit = { request match { case i: RequestWithAttributes[_] => i.set(NonBlockingJS(div), jscript) case _ => } }
inlineNonBlockingJS.scala.html
@import views.support.JavascriptPage @(implicit request: Request[_]) <script src="/javascripts/your_javascript_app.js"></script> <script id="non-blocking" type="text/javascript"> @defining(JavascriptPage.getNonBlockingJS()) { scripts => @scripts.map { case (_, item) => @item } } </script>
It basically wraps the request (using the composition of the game action) with the case class, which has TrieMap as one of its members, which will then serve as the holder of additional attributes attached to the request, and these attributes can be javascript elements and much more that you could would wish and share during the request.