Why doesn't this pass multiple HTML parameters

2019-06-04 18:12发布

问题:

I know about this and this, but the answers are very strange, and in any case, I am looking to understand why this particular approach does not work:

@myPackage.views.html.ol(
  {
    Hello
  }, {
    World
  }
)

myPackage.views.html.ol.scala.html

@(ol:Html*)

<ol>
  @for(li <- ol) {
    <li>
      (hi)
      <span class="li-body">@li</span>
    </li>  
  }
</ol>

Error:

not found: value Hello

I must lack fundamental understanding about the rules of the template engine, because this seems intuitively correct to me.

回答1:

The @ character marks the beginning of a dynamic statement, so you are no longer in template syntax. It's trying to interpret the arguments to the ol() function as straight Scala/Java code, not the template syntax.

It depends on what exactly you're trying to do, but here are two ways to do it. You could probably also use the @defining helper.

@myPackage.views.html.ol(Html("Hello"), Html("World"))

Another way is to define the Html blocks at the beginning of your view.

@html1 = { Hello }
@html2 = { <strong>World</strong> }

@main(){
  @myPackage.views.html.ol(html1, html2)
}


回答2:

estimatic's answer was correct.

Of what he presented, I would probably have used the @html1 = ... solution, but I found something else, which I hope will benefit some future reader.

HtmlVarArgs.scala

import play.api.templates.Html
import scala.collection.mutable.ListBuffer

class HtmlVarArgs(html: Html) {
  private val templates = ListBuffer(html)

  def apply(html: Html) = {
    templates += html
    this
  }

  def passTo(f: Seq[Html] => Html) = f(templates)
}

object HtmlVarArgs {
  def apply(html: Html) = new HtmlVarArgs(html)
}

ol.scala.html

myPackage.views.html.ol.scala.html

@(ol:Html*)

<ol>
  @for(li <- ol) {
    <li>
      (hi)
      <span class="li-body">@li</span>
    </li>  
  }
</ol>

And then I can use it in a template as follows:

@HtmlVarArgs {
  Hello
} {
  World
}.passTo(myPackage.views.html.ol.apply)