Search code examples
scalaplayframework-2.2

How to shuffle between Play! templates in Scala


I have a wrapper template that looks like this:

@(first: Html, second:Html, third:Html)
<div class="wrapper">
@first
@second
@third
</div>

I have three templates I want to shuffle and place as first, second and third. Let's name them: views.html.a, views.html.b, views.html.c.

The controller code:

val a = views.html.a
val b = views.html.b
val c = views.html.c

val list = Random.shuffle(List(a, b, c)) // Will use Random.shuffle here but it fails complication either way

Ok(views.html.wrapper(list(0)(), list(1)(), list(2)()))

The complication error:

play.templates.BaseScalaTemplate[play.api.templates.HtmlFormat.Appendable,play.templates.Format[play.api.templates.HtmlFormat.Appendable]] does not take parameters

It appears as entering the object to the List and getting it out tricks the compiler.

If I don't use list and do:

Ok(views.html.wrapper(a(), b(), c()))

it works as expected and renders the page.

I know I can move the random logic to the wrapper template but I prefer to understand / fix the current implementation and learn some Scala in the process.

Thanks

EDIT

After reading serejja's answer, I'll add complexity to the question since this better represents the problem I'm facing. The three templates need to take a boolean so views.html.a looks like:

@(checkMe:Boolean)
<div ...

So I can't use parentheses before the shuffle. Only after the shuffle occur I wish to send true false true as the booleans.

Using this approach:

Ok(views.html.wrapper(list(0)(true), list(1)(false), list(2)(true)))

gives the following compilation error:

play.templates.BaseScalaTemplate[play.api.templates.Html,play.templates.Format[play.api.templates.Html]] with play.api.templates.Template1[Boolean,play.api.templates.Html] does not take parameters

Solution

  • You were almost there :)

    val a = views.html.a()
    val b = views.html.b()
    val c = views.html.c()
    

    Notice the parentheses. The type of a, b and c now is play.api.templates.HtmlFormat.Appendable instead of the one before.

    Now you can pass it as you wanted:

    Ok(views.html.wrapper(list(0), list(1), list(2)))
    

    EDIT:

    Ok, I cannot imagine what you are up to (so that the solution could be simplified if possible) but I found a workaround.

    First, consider that views a, b and c are on the one level of hierarchy:

                      / a
    BaseScalaTemplate - b
                      \ c
    

    For this solution to work, these views must have the same number of parameters (a(check: Boolean), b(check: Boolean), c(check: Boolean)) so that they make a List[play.templates.BaseScalaTemplate[play.api.templates.Html,play.templates.Format[play.api.templates.Html]] with play.api.templates.Template1[Boolean,play.api.templates.Html]] (which means "a generic template with one Boolean parameter").

    play.api.templates.Template1 has a method render which takes that parameter and returns you a HtmlFormat.Appendable (which I mentioned earlier).

    Considering this your solution might be like this:

    val a = views.html.a
    val b = views.html.b
    val c = views.html.c
    
    val randomizedViews = Random.shuffle(List(a, b, c))
    
    Ok(views.html.wrapper(list(0).render(true), list(1).render(false), list(2).render(true)))
    

    Note that this solution is far from being perfect and I'd suggest you not to use it in real life. I dont think views are intended to be used this way.