入力フォームを作成する作業をパターン化して、記述量を軽減しようとする試み。
#{field 'user.name' } <input ... /> #{/field}
のようにフォーム部分を挟んで使う。
挟まれたコード内では、field
という変数が有効となり、下記のプロパティを参照することができる。
プロパティ | 説明 |
---|---|
id | 引数のドットをアンスコに変換した文字列。'user.name' → 'user_name' |
name | 引数そのまま。'user.name' → 'user.name' |
flash | flash.get(引数) で取得した値。 |
flashArray | flash.get(引数) で取得した値をカンマ区切りのデータとして、配列にしたもの。 |
error | Validation.error(引数) で取得された値。 |
errorClass | Validarion.error(引数) で値が取得された時、 "hasError" という文字列を設定する。例)cssでhasErrorクラスを作っておき、 <span class="${field.errorClass}">${field.error}</span> |
value | 引数の値を設定する。階層は2階層目まで対応。'user.zipcode' はOKだが、'user.address.city' とかはNG。常に field 変数を使ったコードのみを記述できるので、入力フォームコードの共有が容易になる。 |
常にfield
変数を使ったコードのみで記述できるので、入力フォームコードの共通部品化が容易になる。
#{field 'user.name'}
<p>
<label>&{field.name}</label>
<input type="text" id="${field.id}" name="${field.name}" value="${field.value}" class="${field.errorClass}">
<span class="error">${field.error}</span>
</p>
#{/field}
注意
${field.value}
については、#{field}
タグを置いたスコープで取得する変数が参照できることが大前提にある。
以下に例を示す。
public class Application extends Controller {
public static void index() {
render(user);
}
}
#{field 'user.name'}
この場所なら ${field.value} は有効。
#{/field}
#{orginalTag 'user.name' /}
#{field _arg}
この場所だと ${field.value} は無効となる。ここでは変数'user'が有効でないから、${user.name}の値を取得できない。
#{/field}
対策としては、呼出元でsetタグを用いてグローバル変数化する。こうするとタグがネストされていても、変数を参照できる。
#{set user:user /}
#{originalTag 'user.name' /}
蛇足(2021/11/4追記)
${field.value}
でオブジェクト内のプロパティ値を参照する際('user.name'
など)は、オブジェクトのJavaBeanであることを前提として getterメソッドにて値取得を試みる。
play1では play.classloading.enhancers.PropertiesEnhancer.PropertiesEnhancer
により、publicでJavaBeanの命名規則に従っているプロパティに対して自動的にgetter/setterが生成される仕組みがある。そのため特に意識しなくても上記の値取得が成功する。
逆に言うとJavaBeanに従っていないプロパティについては、そのままでは ${field.value}
は動かないことを意味する。
解決方法は簡単で、そのようなプロパティについては自分でgetterを実装する。
独自のEnhancerを作成して透過的にgetterが作成されるようにする方法もあるにはあるが、ちょっと労力に見合わないように思う。