Scala Play template vararg HtmlContent
Asked Answered
A

1

8

I have a generic template in play 2.6, that I want to pass in a variable amount of HtmlContents. I've defined the template like this (including the implicit parameter I have in case that changes anything):

@(foo: String)(content: Html*)(implicit bar: Bar)

On the template side, this works fine-- I can dissect content with for and render it as I want. However, I haven't been able to figure out a clean way to invoke the variable arguments from the underlying template.

e.g, I have a view named "Baz":

@(something: String)(implicit bar: Bar)

In it, I try to invoke the template with multiple Html arguments. I've tried the following:

@template("fooString"){{123},{abc}}
and
@template("fooString")({123}, {abc})
and
@template("fooString"){{123}, {abc}})

And various other permutations, but inside of an enclosing bracket it seems to interpret everything literally as a single parameter in the HtmlContent vararg.

However, this ended up working as I intended, passing in multiple HtmlContents:

@template("fooString")(Html("123"), Html("abc"))

So that works, and I can use a triple-quoted interpolated string for a large Html block-- but it seems like there should be a cleaner way to do this, and the string interpolation is dangerous as it doesn't do html escaping.

Is there a way to do this using the { enclosed syntax? I'd like to understand more what is actually happening on an underlying level, and how play parses and generates HtmlContent in brackets.

Armandarmanda answered 25/11, 2016 at 18:45 Comment(2)
Your Html(...) approach looks quite clean and explicit to me. The Twirl source code could be one place to try and dig further into your question though.Phiz
Any comments on the answer I posted?Meader
M
2

So consider you have below template

// main.scala.html
@(title: String)(contents: Html*)

There are different ways you can call this template

Option #1

This is what you already posted in the question

@main("This is a title")(Html("abc"), Html("123"))

Options #2

@html1 = {
    Hello
}
@html2 = {
    <div>Tarun</div>
}

@main("This is a title")(html1, html2)

Option #3

@main("This is a title")(Html(<div>Tarun
</div>.toString), Html(<div>
Lalwani
</div>.toString))

Options #4

This is not exactly same option, but needs change in Template signature itself

@(title: String)(contents: List[String])  

And then calling it like below

@main("This is a title")(List(
  """<div>
     Tarun
    </div>
  """, """Hello"""))

Option #5

This requires code files and was already answered on another SO thread

Paul Draper's answer on Why doesn't this pass multiple HTML parameters to template

Meader answered 9/10, 2017 at 17:47 Comment(1)
Any explanation for the downvote? Its best to comment with a downvoteMeader

© 2022 - 2024 — McMap. All rights reserved.