En mi opinión, el hecho de que las plantillas estén estáticamente escritas es realmente bueno : tiene la garantía de que llamar a su plantilla no fallará si se compila.
Sin embargo, de hecho agrega algo repetitivo en los sitios de llamadas. Pero puede reducirlo (sin perder las ventajas de la escritura estática).
En Scala, veo dos formas de lograrlo: a través de la composición de acciones o mediante el uso de parámetros implícitos. En Java sugiero usar el Http.Context.args
mapa para almacenar valores útiles y recuperarlos de las plantillas sin tener que pasarlos explícitamente como parámetros de plantillas.
Usando parámetros implícitos
Coloque el menus
parámetro al final de los main.scala.html
parámetros de su plantilla y márquelo como "implícito":
@(title: String)(content: Html)(implicit menus: Seq[Menu])
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu<-menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
Ahora, si tiene plantillas que llaman a esta plantilla principal, puede hacer que el compilador Scala menus
pase el parámetro implícitamente a la main
plantilla si también se declara como un parámetro implícito en estas plantillas:
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
Pero si desea que se pase implícitamente desde su controlador, debe proporcionarlo como un valor implícito, disponible en el ámbito desde donde llama a la plantilla. Por ejemplo, puede declarar el siguiente método en su controlador:
implicit val menu: Seq[Menu] = Menu.findAll
Luego, en sus acciones, podrá escribir lo siguiente:
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
Puede encontrar más información sobre este enfoque en esta publicación de blog y en este ejemplo de código .
Actualización : Aquí también se ha escrito una buena publicación de blog que demuestra este patrón .
Usar composición de acciones
En realidad, a menudo es útil pasar el RequestHeader
valor a las plantillas (ver, por ejemplo, esta muestra ). Esto no agrega tanto repetitivo a su código de controlador porque puede escribir fácilmente acciones que reciben un valor de solicitud implícito:
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
Entonces, dado que las plantillas a menudo reciben al menos este parámetro implícito, puede reemplazarlo con un valor más rico que contenga, por ejemplo, sus menús. Puedes hacerlo utilizando el mecanismo de composición de acciones de Play 2.
Para hacerlo, debe definir su Context
clase, ajustando una solicitud subyacente:
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
Luego puede definir el siguiente ActionWithMenu
método:
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
Que se puede usar así:
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
Y puede tomar el contexto como un parámetro implícito en sus plantillas. Por ejemplo para main.scala.html
:
@(title: String)(content: Html)(implicit context: Context)
<html><head><title>@title</title></head>
<body>
<div>
@for(menu <- context.menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
El uso de la composición de acciones le permite agregar todos los valores implícitos que requieren sus plantillas en un solo valor, pero por otro lado puede perder algo de flexibilidad ...
Usando Http.Context (Java)
Dado que Java no tiene el mecanismo de implicaciones de Scala o similar, si desea evitar pasar parámetros de plantillas explícitamente, una posible forma es almacenarlos en el Http.Context
objeto que vive solo durante la duración de una solicitud. Este objeto contiene un args
valor de tipo Map<String, Object>
.
Por lo tanto, puede comenzar escribiendo un interceptor, como se explica en la documentación :
public class Menus extends Action.Simple {
public Result call(Http.Context ctx) throws Throwable {
ctx.args.put("menus", Menu.find.all());
return delegate.call(ctx);
}
public static List<Menu> current() {
return (List<Menu>)Http.Context.current().args.get("menus");
}
}
El método estático es solo una abreviatura para recuperar los menús del contexto actual. Luego anote su controlador para mezclarlo con el Menus
interceptor de acción:
@With(Menus.class)
public class Application extends Controller {
// …
}
Finalmente, recupere el menus
valor de sus plantillas de la siguiente manera:
@(title: String)(content: Html)
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu <- Menus.current()) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>