In Kohana (PHP framework) the layout is implemented through Template_Controller which continas a member variable called $template, which serves as layout view. Then in the action method you can populate the $template with further sub-views, usually the content view. (http://forum.kohanaframework.org/discussion/3612/kohana-layout-system/p1)
This allows me to change the layout "theme" in the runtime. It is useful for multitenant system, where a tenant can select their own theme (two col, three col, etc.)
How can I achieve that in playframework 2 Scala, with Scala template engine? In other words, I'd like to have multiple layout templates in which a tenant can select from. The controller then renders the layout template and the action specific content template.
Something like (Controller's action pseudocode):
Note: for each action, the layout theme may change per user but the content view remains same.
In it's documentation (http://www.playframework.com/documentation/2.1.1/ScalaTemplateUseCases)
the content template, say, the index.scala.html, includes a call to the main which is defined in main.scala.html, the layout template. In other words, it is hard coded, thus index.scala.html is tightly coupled to main.scala.html.
I though about calling the main from the controller using reflection, and then passing the content.
An alternative would be to use a interpreted template engine such as Scalate.
Any suggestion?
I see 2 options to accomplish what you're after. The first would be to pass a theme parameter to your templates (i.e. something to tell the called template which theme/layout to use) and use that parameter to conditionally call a layout template. The second would be to handle the condition inside the controller by returning the appropriate view based on the selected theme.
Option 1
In your action you will want to pass some value to your template to indicate which theme to use.
def index = Action {
Ok(views.html.index("two-col"))
}
Then in your index.scala.html
you would do something like this:
@(theme: String)
@content = {
<h1>Action Specific Content</h1>
}
@if("two-col" eq theme) {
@twoCol("title")(content)
} else {
@main("title")(content)
}
This would expect there to be a twoCol.scala.html
template, such as:
@(title: String)(content: Html)
<!DOCTYPE html>
<html>
...
<body>
<h1>Two Column</h1>
@content
</body>
</html>
Note: You can also pass the theme using an implicit parameter, see this SO question. This would alleviate the need to explicitly pass it the template on every render.
Option 2
This would be as simple as the following in your controller, but would possibly require much more repeated code in the view templates.
def index = Action {
var theme = ...
...
if (theme eq 'tow-col') {
Ok(views.html.twocol.index("two-col"))
} else {
Ok(views.html.default.index())
}
This assumes there is a twocol
and default
package in /app/views
that have an index.scala.html
.
Additional Comments
As you can tell from option 1, index.scala.html is not tightly coupled with main.scala.html. You can replace the call to main with a call to any other template, or even no template.
FWIW, I would go with option 1 and It would possibly evolve into a better solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With