Search code examples
scalaplayframeworkplayframework-2.3twirl

Can't concatenate play.twirl.api.Html objects with play 2.3


I am trying to migrate a rather large project from play framework 2.2 to 2.3. In the project we have some helpers that do something like this:

import play.api.templates.Html;
...
private object HtmlHelper {
  ...
  // Given a sequence of Htmls, return a single Html containing them
  def html(htmls: Seq[Html]): Html = htmls.foldLeft(Html(""))(_+=_)
}

I have converted it to this:

import play.twirl.api.Html;
...
private object HtmlHelper {
  ...
  // Given a sequence of Htmls, return a single Html containing them
  def html(htmls: Seq[Html]): Html = htmls.foldLeft(Html(""))((r,c) => r + c)
}

This fails to compile with the following error:

Read from stdout: <PATH> type mismatch;
Read from stdout: found   : play.twirl.api.Html
Read from stdout: required: String

I've been trying to find documentation on this Html object in 2.3 but have had no luck finding anything. As far as I can see, the Html object implements Appendable, which means the + operator should work... I don't have time to learn all of Scala and this supposed "expressive" syntax is getting on my nerves.

Any help would be appreciated.


Solution

  • There is no more += method defined on Html, so the compiler tries to make it work as a String, which also doesn't work. See the updated scaladoc (Html is a type of Appendable).

    This used to support +=, but no longer is required to.

    @todo Change name to reflect not appendable

    I guess you could combine the String values, then convert back to Html.

    def html(htmls: Seq[Html]): Html =
        Html(htmls.foldLeft("")((r, c) => r + c.toString))
    
    scala> val list = List(Html("<p>1</p>"), Html("<p>2</p>"), Html("<p>3</p>"))
    list: List[play.twirl.api.Html] = List(<p>1</p>, <p>2</p>, <p>3</p>)
    
    scala> html(list)
    res5: play.twirl.api.Html = <p>1</p><p>2</p><p>3</p>
    

    There is actually a method called fill that already does this, though, in HtmlFormat:

    def html(htmls: Seq[Html]): Html = HtmlFormat.fill(htmls)
    

    It might be finicky a bit with Seq.