I'd prefer to use the former over the latter, but am not sure how to incorporate Scalatags into the playframework.
This is my simple layout:
object Test
{
import scalatags.Text.all._
def build =
{
html(
head(
title := "Test"
),
body(
h1("This is a Triumph"),
div(
"Test"
)
)
)
}
}
This is how I try to render it:
Ok(views.Test.build.render)
Problem is, that I get it as a plain String, not as HTML.
Now, of course one solution would be to simply append.
Ok(views.Test.build.render).as("text/html")
but is that really the only way? (Without creating a helper method that is)
I assume you want to be able to call Ok(views.Test.build)
. Play is ignorant of ScalaTags so we're going to have to write something ourselves here.
Play uses a bit of implicit machinery to generate HTTP responses. When you call Ok(...)
you're actually calling apply
on the play.api.mvc.Results
trait. Let's take a look at its signature:
def apply[C](content: C)(implicit writeable: Writeable[C]): Result
So we can see that we need an implicit Writeable[scalatags.Text.all.Tag]
:
implicit def writeableOfTag(implicit codec: Codec): Writeable[Tag] = {
Writeable(tag => codec.encode("<!DOCTYPE html>\n" + tag.render))
}
Don't forget to include a doctype declaration. ScalaTags doesn't give you one.
That call to Writeable.apply
itself requires another implicit to determine the content type. Here is its signature:
def apply[A](transform: A => ByteString)(implicit ct: ContentTypeOf[A]): Writeable[A]
So let's write an implicit ContentTypeOf[Tag]
:
implicit def contentTypeOfTag(implicit codec: Codec): ContentTypeOf[Tag] = {
ContentTypeOf[Tag](Some(ContentTypes.HTML))
}
This allows us to avoid having to write as("text/html")
explicitly and it includes the charset (courtesy of the implicit codec), resulting in a Content-Type
header of text/html; charset=utf-8
.
Putting it all together:
import play.api.http.{ ContentTypeOf, ContentTypes, Writeable }
import play.api.mvc.Results.Ok
import scalatags.Text.all._
def build: Tag = {
html(
head(
title := "Test"
),
body(
h1("This is a Triumph"),
div(
"Test"
)
)
)
}
implicit def contentTypeOfTag(implicit codec: Codec): ContentTypeOf[Tag] = {
ContentTypeOf[Tag](Some(ContentTypes.HTML))
}
implicit def writeableOfTag(implicit codec: Codec): Writeable[Tag] = {
Writeable(tag => codec.encode("<!DOCTYPE html>\n" + tag.render))
}
def foo = Action { implicit request =>
Ok(build)
}
You probably want to tuck those implicits somewhere convenient and then import them in your controller(s).