Menurut pendapat saya, fakta bahwa templat diketik secara statis sebenarnya baik hal yang : Anda dijamin bahwa memanggil templat Anda tidak akan gagal jika dikompilasi.
Namun, itu memang menambahkan beberapa boilerplate di situs panggilan. Tapi Anda bisa menguranginya (tanpa kehilangan keunggulan pengetikan statis).
Di Scala, saya melihat dua cara untuk mencapainya: melalui komposisi aksi atau dengan menggunakan parameter implisit. Di Jawa saya sarankan menggunakanHttp.Context.args
peta untuk menyimpan nilai-nilai berguna dan mengambilnya dari template tanpa harus secara eksplisit lulus sebagai parameter template.
Menggunakan parameter implisit
Tempatkan menus
parameter di akhir main.scala.html
parameter template Anda dan tandai sebagai "implisit":
@(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>
Sekarang jika Anda memiliki template yang memanggil template utama ini, Anda dapat memiliki menus
parameter yang secara implisit dilimpahkan untuk Anda ke main
templat oleh kompilator Scala jika dinyatakan sebagai parameter implisit dalam templat ini juga:
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
Tetapi jika Anda ingin secara implisit dilewatkan dari pengontrol Anda, Anda harus memberikannya sebagai nilai implisit, tersedia dalam ruang lingkup tempat Anda memanggil templat. Misalnya, Anda dapat mendeklarasikan metode berikut di controller Anda:
implicit val menu: Seq[Menu] = Menu.findAll
Maka dalam tindakan Anda, Anda hanya dapat menulis yang berikut ini:
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
Anda dapat menemukan informasi lebih lanjut tentang pendekatan ini di posting blog ini dan di contoh kode ini .
Memperbarui : Posting blog yang bagus menunjukkan pola ini juga telah ditulis di sini .
Menggunakan komposisi aksi
Sebenarnya, sering berguna untuk meneruskan RequestHeader
nilai ke templat (lihat misalnya sampel ini ). Ini tidak menambah terlalu banyak pelat ke kode pengontrol Anda karena Anda dapat dengan mudah menulis tindakan yang menerima nilai permintaan implisit:
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
Jadi, karena templat sering menerima setidaknya parameter implisit ini, Anda bisa menggantinya dengan nilai yang lebih kaya yang mengandung misalnya menu Anda. Anda dapat melakukannya dengan menggunakan komposisi aksi mekanisme dari Play 2.
Untuk melakukan itu Anda harus mendefinisikan Context
kelas Anda , membungkus permintaan yang mendasarinya:
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
Kemudian Anda dapat menentukan ActionWithMenu
metode berikut :
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
Yang bisa digunakan seperti ini:
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
Dan Anda dapat mengambil konteks sebagai parameter implisit dalam template Anda. Misalnya untuk 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>
Menggunakan komposisi tindakan memungkinkan Anda untuk mengumpulkan semua nilai implisit yang diperlukan template Anda menjadi nilai tunggal, tetapi di sisi lain Anda dapat kehilangan beberapa fleksibilitas ...
Menggunakan Http.Context (Java)
Karena Java tidak memiliki mekanisme implisit Scala atau yang serupa, jika Anda ingin menghindari untuk secara eksplisit melewatkan parameter templat, cara yang mungkin adalah dengan menyimpannya di Http.Context
objek yang hanya hidup selama durasi permintaan. Objek ini mengandung args
nilai tipeMap<String, Object>
.
Dengan demikian, Anda bisa mulai dengan menulis interseptor, seperti yang dijelaskan dalam dokumentasi :
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");
}
}
Metode statis hanyalah singkatan untuk mengambil menu dari konteks saat ini. Lalu beri catatan pengontrol Anda untuk dicampur dengan Menus
tindakan pencegat:
@With(Menus.class)
public class Application extends Controller {
// …
}
Terakhir, ambil menus
nilai dari templat Anda sebagai berikut:
@(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>