0

I was trying to make the Play layout a bit more dynamic, but didn't know how, any help??

My problem goes like :

index.scala.html

@(title: String,templateName:String) // templateName is data obtained from a db src,  

@templates.(@templateName)(title,templateName){ // I wanted to put value of templateName after @template.****, so that template names get set at compile time, but of course it gives out errors
}

Inside view -> templates -> main.scala.html, foo.scala.html, bar.scala.html

I am not saying that I need to make the whole 'Main-Layout' dynamically but, just get the names dynamically. Can it be done??

I tried doing it like below, but I will need to know every templates name, any suggestions

index.scala.html

@(title: String,templateName:String)

@if(templateName == "foo"){
    @templates.foo(title,templateName){
    }
}
else if(templateName == "bar"){
    @templates.bar(title,templateName){
} else {
    ......
}

I guess I didn't explain my issue properly:

@johanandren Well there seems to be some misunderstanding. Yes I do understand now that I am not allowed to give template name dynamically (if reflection isn't used, and it seems to have its own cons as well,thanks to you and @Khanser)from the controller, which I never was planning to do at all.

But like you have said "If you just want to apply common templating around your individual sub-templates", my main concern is that I wont have a common templating, as you have stated , infact based on the user => different main template. Yes I could use the switch/case for my purpose but I'll need to know * template names and hardcode them on each and every sub-template.

And Yes, I have understood the use of "templates->main.scala.html" and "sub-templates=>index.scala.html" etc,etc.... and injecting sub-templates on main templates. And I think I have already been doing this invert the template flow.

mane
  • 1,149
  • 16
  • 41

2 Answers2

0

You can't use it like you want, however you can make use of Scala Dynamics.

Create a class extending the Dynamic scala trait, with something like this:

object DynamicTemplates extends scala.Dynamic{
    def applyDynamic(methodName:String)(someParam:String) ={
        if(methodName == "foo") templates.foo(someParam)
        else whatever
    }
}

This way you can either do this 2 things:

DynamicTemplates.foo("someParam")

or

DynamicTemplates.selectDynamic(templateName)("someParam")
Rubén
  • 524
  • 5
  • 22
  • Can you please explain a bit of what you are doing, cause I couldn't understand why are doing that, Scala newbies here,sorry!! I actually need dynamic functionality when choosing main.scala.html, not in this line Ok(views.templates.main("foos")). `You can't use it like you want` isn't what I am trying to do not possible at all in scala templates?? – mane May 08 '14 at 01:56
  • @mane in Scala you can't use "meta"-dynamic method calling based on a string like you can on php or javascript. However Scala gives you the Dynamic trait that will let you call unexisting methods on a class like if it actually were defined there. Instead of doing, like in php `$obj->{$methodName}($arg1, $arg2, $arg3);` in scala you do `obj.selectDynamic(methodName)(arg1,arg2)` or `obj.methodName(arg1,arg2)` but you can't use a string to dynamically call the method unless you use the first form.More info: http://stackoverflow.com/questions/15799811/how-does-type-dynamic-work-and-how-to-use-it – Rubén May 08 '14 at 13:00
0

Each template gets compiled into a class with one method, calling the template is not dynamic but just like calling any other method/function in Scala or Java. Making this dynamic is possible using reflection but you will loose the static type check that ensures that you will get a compiler error if you try to call a template that does not exist or use parameters that does not match the parameter list of the individual template.

There might some use cases where you absolutely need this kind of dynamic template handling (like if you select which template to use with a database flag) but the way you have done it with an if else, or more concisely using a Scala switch/match, is probably the best since you get explicit code that will fail to compile if you do it wrong, as opposed to reflection stuff that wouldn't fail until runtime when that specific template was used.

If you just want to apply common templating around your individual sub-templates, the same header for example, then the common way to do this is to invert the template flow so that each individual template will call a "main" template passing their content as a HTML parameter that the main template will incude in the common structure.

This is how the sample play project templates are setup when you create a new project, so you can look at that, index.scala.html will call main.scala.html which contains the common markup.

johanandren
  • 11,249
  • 1
  • 25
  • 30
  • please look thorugh the edit. And I guess I am better off using the `switch/match`, and I could try to re-use the switch and match statement, creating some snippets or tags or something, whatever play provides. – mane May 12 '14 at 04:42
  • Since each template is "just a function" (should be able to handle whatever logic you ascribe to snippet/tag) you can easily create templates which is just common logic. It is also possible and sometimes easier to create regular Scala helper functions to do that kind of stuff and call those from the templates. Also, if each user has got a separate distinct template then maybe a more dynamic template engine (or even client side templates) could be a good idea for you. – johanandren May 12 '14 at 09:01