Play1では、通常、すべてのデータをアクションで取得し、ビューで直接使用します。ビューでパラメーターを明示的に宣言する必要がないため、これは非常に簡単です。
しかし、play2では、ビューの先頭ですべてのパラメーター(request
を含む)を宣言する必要があることがわかりました。すべてのデータをアクションで取得してビューに渡すのは非常に退屈です。
たとえば、データベースからロードされたメニューをフロントページに表示する必要がある場合は、_main.scala.html
_で定義する必要があります。
_@(title: String, menus: Seq[Menu])(content: Html)
<html><head><title>@title</title></head>
<body>
<div>
@for(menu<-menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body></html>
_
次に、すべてのサブページで宣言する必要があります。
_@(menus: Seq[Menu])
@main("SubPage", menus) {
...
}
_
次に、メニューを取得し、すべてのアクションで表示するために渡す必要があります。
_def index = Action {
val menus = Menu.findAll()
Ok(views.html.index(menus))
}
def index2 = Action {
val menus = Menu.findAll()
Ok(views.html.index2(menus))
}
def index3 = Action {
val menus = Menu.findAll()
Ok(views.html.index(menus3))
}
_
現時点では、_main.scala.html
_のパラメーターは1つだけですが、多数ある場合はどうなりますか?
ようやく、すべてのMenu.findAll()
を直接表示することにしました:
_@(title: String)(content: Html)
<html><head><title>@title</title></head>
<body>
<div>
@for(menu<-Menu.findAll()) {
<a href="#">@menu.name</a>
}
</div>
@content
</body></html>
_
それが良いか推奨されているかわかりませんが、これに対するより良い解決策はありますか?
私の意見では、テンプレートが静的に型付けされているという事実は、実際にはgoodのことです。コンパイルしてもテンプレートの呼び出しは失敗しないことが保証されます。
ただし、実際には呼び出し元のサイトに定型句が追加されます。ただし、減らすことができます(静的な型付けの利点を失うことなく)。
Scalaには、アクションを合成する方法と暗黙的なパラメーターを使用する方法の2つの方法があります。 Javaでは、_Http.Context.args
_マップを使用して有用な値を保存し、テンプレートパラメーターとして明示的に渡すことなくテンプレートからそれらを取得することをお勧めします。
menus
パラメーターを_main.scala.html
_テンプレートパラメーターの最後に配置し、「暗黙的」としてマークします。
_@(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>
_
このメインテンプレートを呼び出すテンプレートがある場合、Scalaコンパイラーが暗黙パラメーターとして宣言されている場合、menus
パラメーターをmain
テンプレートに暗黙的に渡すことができます。これらのテンプレートでも:
_@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
_
ただし、コントローラーから暗黙的に渡されるようにする場合は、テンプレートを呼び出すスコープで使用可能な暗黙的な値として提供する必要があります。たとえば、コントローラーで次のメソッドを宣言できます。
_implicit val menu: Seq[Menu] = Menu.findAll
_
その後、アクションで次のように書くことができます。
_def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
_
このアプローチの詳細については、 このブログ投稿 および このコードサンプル を参照してください。
Update:このパターンを示す素敵なブログ投稿も書かれています here 。
実際には、RequestHeader
値をテンプレートに渡すと便利なことがよくあります(例 このサンプル を参照)。暗黙的な要求値を受け取るアクションを簡単に記述できるため、コントローラーコードにそれほどボイラープレートは追加されません。
_def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
_
そのため、テンプレートは少なくともこの暗黙的なパラメータを受け取ることが多いため、たとえば次のようなより豊かな値に置き換えることができます。あなたのメニュー。 Play 2の actions composition メカニズムを使用して、これを行うことができます。
そのためには、Context
クラスを定義し、基になるリクエストをラップする必要があります。
_case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
_
次に、次のActionWithMenu
メソッドを定義できます。
_def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
_
次のように使用できます:
_def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
_
また、テンプレートの暗黙的なパラメーターとしてコンテキストを使用できます。例えば。 _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>
_
アクション構成を使用すると、テンプレートに必要なすべての暗黙的な値を単一の値に集約できますが、一方で柔軟性を失う可能性があります…
JavaにはScalaの暗黙的なメカニズムなどがないため、テンプレートパラメータを明示的に渡すことを避けたい場合、可能な期間は、その期間だけ存続する_Http.Context
_オブジェクトに格納することです要求。このオブジェクトには、タイプ_Map<String, Object>
_のargs
値が含まれます。
したがって、 ドキュメント で説明されているように、インターセプターを記述することから開始できます。
_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");
}
}
_
静的メソッドは、現在のコンテキストからメニューを取得するための単なる省略形です。次に、コントローラーに注釈を付けてMenus
アクションインターセプターと混合します。
_@With(Menus.class)
public class Application extends Controller {
// …
}
_
最後に、次のようにテンプレートからmenus
値を取得します。
_@(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>
_
私のやり方は、ナビゲーション/メニュー用の新しいコントローラーを作成し、ビューから呼び出すだけです。
NavController
を定義できます:
object NavController extends Controller {
private val navList = "Home" :: "About" :: "Contact" :: Nil
def nav = views.html.nav(navList)
}
nav.scala.html
@(navLinks: Seq[String])
@for(nav <- navLinks) {
<a href="#">@nav</a>
}
次に、メインビューでNavController
を呼び出すことができます。
@(title: String)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
@NavController.nav
@content
</body>
</html>
Stianの答えを支持します。これは、結果を得るための非常に迅速な方法です。
Java + Play1.0からJava + Play2.0に移行したばかりで、テンプレートはこれまでで最も難しい部分であり、ベーステンプレート(タイトル、ヘッドなど)を実装するために見つけた最良の方法は、Httpを使用することです。状況。
タグで実現できる非常に素晴らしい構文があります。
views
|
\--- tags
|
\------context
|
\-----get.scala.html
\-----set.scala.html
get.scala.htmlは次のとおりです。
@(key:String)
@{play.mvc.Http.Context.current().args.get(key)}
set.scala.htmlは次のとおりです。
@(key:String,value:AnyRef)
@{play.mvc.Http.Context.current().args.put(key,value)}
テンプレートに以下を書くことができることを意味します
@import tags._
@context.set("myKey","myValue")
@context.get("myKey")
とても読みやすくて素敵です。
これが私が選んだ道です。 stian-良いアドバイス。すべての回答を表示するには、下にスクロールすることが重要です。 :)
Html変数を渡す方法はまだわかりません。
@(title:String、content:Html)
ただし、それらをブロックとして渡す方法は知っています。
@(title:String)(content:Html)
したがって、set.scala.htmlを次のように置き換えることができます。
@(key:String)(value:AnyRef)
@{play.mvc.Http.Context.current().args.put(key,value)}
このようにして、Htmlブロックを渡すことができます
@context.set("head"){
<meta description="something here"/>
@callSomeFunction(withParameter)
}
Playでの一般的なユースケースのテンプレート継承。
Base_template.htmlがあり、次にbase_template.htmlを拡張するpage_template.htmlがあります。
base_template.htmlは次のようになります
<html>
<head>
<title> @context.get("title")</title>
</head>
<body>
@context.get("body")
</body>
</html>
ページテンプレートは次のようになります
@context.set("body){
some page common context here..
@context.get("body")
}
@base_template()
次のようなページ(login_page.htmlを想定)があります
@context.set("title"){login}
@context.set("body"){
login stuff..
}
@page_template()
ここで注意すべき重要なことは、「body」を2回設定することです。 「login_page.html」に一度、次に「page_template.html」に。
上記のようにset.scala.htmlを実装している限り、これは副作用を引き起こすようです。
@{play.mvc.Http.Context.current().put(key,value)}
putは同じキーを2回入力したときに表示される値を返すため、ページには「login stuff ...」が2回表示されるためです。 (Java docs)の署名を参照してください。
scalaはマップを変更するより良い方法を提供します
@{play.mvc.Http.Context.current().args(key)=value}
この副作用は発生しません。
Javaを使用しており、インターセプターを作成せずに@Withアノテーションを使用せずに可能な限り単純な方法が必要な場合は、テンプレートからHTTPコンテキストに直接アクセスすることもできます。
例えば。テンプレートから使用可能な変数が必要な場合は、次のコマンドを使用してHTTPコンテキストに追加できます。
Http.Context.current().args.put("menus", menus)
次に、テンプレートから次のコマンドでアクセスできます。
@Http.Context.current().args.get("menus").asInstanceOf[List<Menu>]
Http.Context.current()。args.put( ""、 "")を使用してメソッドをポイ捨てする場合は、インターセプターを使用する方が良いことは明らかですが、単純な場合にはトリックを実行できます。
Stianの答えから、私は別のアプローチを試みました。これは私のために動作します。
IN Java CODE
import play.mvc.Http.Context;
Context.current().args.put("isRegisterDone", isRegisterDone);
HTMLテンプレートヘッド
@import Http.Context
@isOk = @{ Option(Context.current().args.get("isOk")).getOrElse(false).asInstanceOf[Boolean] }
のように使用
@if(isOk) {
<div>OK</div>
}