たそらぼ

日頃思ったこととかメモとか。

Play Framework 2.7.xのフォームに独自レイアウトを適用する

play frameworkのフォームのテキストボックスにデフォルトで出てくる”Required”などの文字を消す方法です。
Field constructors(Java Form Helpers - 2.7.x)を自分で定義することで解決できました。
日本語文献もみつけたので、最後にまとめます。

play frameworkのフォームに文字が出る問題

f:id:tasotasoso:20190731164005p:plain
modelで@Constraints.Requiredなどを使っているとき、Formのヘルパー関数でFormを作ると、テキストボックスなどの下に文字が出てきますよね。なかなか必要ない...。身の回りだとヘルパー関数を使わずにふつうにFormタグで作ってしまうことで回避しているケースが多いのですが、play内蔵のCSRFフィルタが使えなくなってしいますし、play的にはどうやって使うべきなのか困ってきました。

検証環境

生成されたコンポーネントの確認

該当箇所(下図)のHTMLを確認します。
f:id:tasotasoso:20190731165259p:plain

ブラウザの開発者モードで適当にソースを見てみます。

<dl class=" " id="name_field">
    <dt><label for="name">name</label></dt>
    <dd>
         <input type="text" id="name" name="name" value="" />
    </dd>
    <dd class="info">Required</dd>
</dl>

全く書いた覚えがないのですが、見事に

Required
というのが生成されています。

暗黙のField constructors

公式ページのForm template helpersの章をよーく読むと、Field constructors(Java Form Helpers - 2.7.x)の節に、気になる記述が...。

A rendered field does not only consist of an < input > tag, but may also need a < label > and a bunch of other tags used by your CSS framework to decorate the field. All input helpers take an implicit FieldConstructor that handles this part. The default one (used if there are no other field constructors available in the scope), generates HTML like:

すべての入力ヘルパーは、暗黙のFieldConstructorを取るとのことです。その内容は、

<dl class="error" id="email_field">
    <dt><label for="email">Email:</label></dt>
    <dd><input type="text" name="email" id="email" value=""></dd>
    <dd class="error">This field is required!</dd>
    <dd class="error">Another error</dd>
    <dd class="info">Required</dd>
    <dd class="info">Another constraint</dd>
</dl>

ということで、暗黙のFieldConstructorに

Required
があるので、レンダリングする際に出てきてしまっているようです。

自前のField constructorsの作成

暗黙のFieldConstructorの代わりに、自前のField constructorsを作成し、これを読み込むことで問題が回避できそうなので、Writing your own field constructor(Java Form Helpers - 2.7.x)を見つつ、実装してみます。

以下をmyFieldConstructorTemplate.scala.htmlとして保存し、views/配下に置きます。

@(elements: helper.FieldElements)

<div class="@if(elements.hasErrors) {error}">
<label for="@elements.id">@elements.label</label>
<div class="input">
    @elements.input
</div>
</div>

また、フォームのあるテンプレートに下記を書き足しておきます。なお、もしフォームを"form:play.data.Form[WidgetData]@import helper._"のように宣言している場合は、helper.formと衝突するので注意してください。

@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }

これをレンダリングすると、

f:id:tasotasoso:20190801112959p:plain

Requiredの文字が消えました。よかった。

参考文献

2.6でまとめてくださっている記事がありました。ありがとうございました。
yoshinorin.net