enum オブジェクト プロパティの HTML コンボ ボックスのオプションを事前に選択する際に問題が発生しています。これが私のコードの説明です。CompanyPhone(s) のリストを含む Company モデル クラスがあります。
@Entity
public class Company {
...
@OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
public List<CompanyPhone> phones;
...
}
CompanyPhone には、列挙型の PhoneType タイプの phoneType プロパティがあります。
@Column(name = "PHONE_TYPE")
public PhoneType type;
以下は、HTML テンプレートで選択ボックス オプションを表示するための Map を取得する静的 options() メソッドを使用した PhoneType 列挙型です。
public enum PhoneType {
@EnumValue("MAI") MAIN,
@EnumValue("MOB") MOBILE,
@EnumValue("FAX") FAX,
@EnumValue("CUS") CUSTOM;
public static Map<String, String> options() {
LinkedHashMap<String, String> options = new LinkedHashMap<String, String>();
for (PhoneType v : PhoneType.values()) {
try {
EnumValue a = v.getClass().getField(v.name()).getAnnotation(EnumValue.class);
options.put(a.value(), Messages.get(String.format("%s.%s",
PhoneType.class.getSimpleName(), v.name())));
} catch (NoSuchFieldException | SecurityException e) { /* ignore */ }
}
return options;
}
}
Ebean のドキュメントに基づいて、@EnumValue アノテーションを使用してデータベースに格納される値を指定することにしました。また、PhoneType enum と String の間で変換するフォーマッターを実装し、ルート パッケージの Global.java の onStart メソッドに登録しました。
public class Global extends GlobalSettings {
@Override
public void onStart(Application app) {
Formatters.register(PhoneType.class, new PhoneTypeFormatter());
....
}
...
}
参考までに、フォーマッタ クラスを次に示します。
public class PhoneTypeFormatter extends SimpleFormatter<PhoneType> {
@Override
public PhoneType parse(String input, Locale locale) throws ParseException {
PhoneType phoneType = null;
for (PhoneType v : PhoneType.values()) {
try {
EnumValue a = v.getClass().getField(v.name()).getAnnotation(EnumValue.class);
if (input != null && a != null && input.equals(a.value())) {
phoneType = v;
break;
}
} catch (NoSuchFieldException | SecurityException e) { /* ignore */ }
}
return phoneType;
}
@Override
public String print(PhoneType phoneType, Locale locale) {
String v = null;
try {
v = (phoneType.getClass().getField(phoneType.name())
.getAnnotation(EnumValue.class)).value();
} catch (NoSuchFieldException | SecurityException e) { /* ignore */ }
return v;
}
}
ここで、複数の電話の入力フィールドを表示するために、HTML テンプレート ファイルで Play2 @repeat ディレクティブを使用します。ここに抜粋があります:
...
@phoneGroup(field: Field, className: String = "companyPhone") = {
<div class="control-group @className">
<label class="control-label" for="@field("type").id">@Messages("company.phoneNumbers")</label>
<div class="controls">
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null && value == field("type").value) { selected }>@text</option>
}
</select>
<input type="text" class="inputAreaCode" id="@field("areaCode").id"
name="@field("areaCode").name" value="@field("areaCode").value"
placeholder="@Messages("phone.areaCode")">
<input type="text" class="input-medium" id="@field("number").id"
name="@field("number").name" value="@field("number").value"
placeholder="@Messages("phone.number")">
<a class="removePhone btn btn-danger">@Messages("button.remove")</a>
</div>
</div>
}
...
@main {
...
<div class="companyPhones well">
@repeat(companyForm("phones"), min = 1) { phone =>
@phoneGroup(phone)
}
@**
* Keep the hidden block that will be used as template for Javascript copy code.
**@
@phoneGroup(
companyForm("phones[x]"),
className = "companyPhone_template")
<div class="manage_repeat">
<a class="addPhone btn btn-success">@Messages("phone.add")</a>
</div>
</div>
...
}
ここまでは順調ですね。フォームに入力してデータを送信すると、電話番号がデータベースに適切に保存されます。しかし、同じフォームを使用して既存のデータを編集すると、コンボ ボックスで現在の電話の種類のオプションが選択されません。以下で赤くハイライトされた @if ディレクティブは機能しないようです。ただし、エラーは表示されません。
@phoneGroup(field: Field, className: String = "companyPhone") = {
...
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null && value == field("type").value) { selected }>@text</option>
}
</select>
...
}
選択前に @field("type").value の現在の値を span 要素 (青色で強調表示) に表示しようとしましたが、HTML ページの出力値は正しいですが、"FAX" の現在の値は選択されていません。 :
@phoneGroup(field: Field, className: String = "companyPhone") = {
...
<span>Selected type: @field("type").value</span>
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null && value == field("type").value) { selected }>@text</option>
}
</select>
...
}
上記のテンプレートは、次の HTML を出力します。
...
<span>Selected type: FAX</span>
<select id="phones_0__type" name="phones[0].type" class="input-small">
<option value="MAI">Main</option>
<option value="MOB">Mobile</option>
<option value="FAX">Fax</option>
<option value="CUS">Custom</option>
</select>
...
私はここで立ち往生しています。私は Scala に詳しくなく、Scala のテンプレートに関するドキュメントはあまり直感的ではありません。また、「selected」の代わりに @field("type").value の値を表示しようとしました。
@phoneGroup(field: Field, className: String = "companyPhone") = {
...
<span>Selected type: @field("type").value</span>
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null) { @field("type").value }>@text</option>
}
</select>
...
}
そしてそれは正しい値を出力しますが、小文字で:
...
<span>Selected type: FAX</span>
<select id="phones_0__type" name="phones[0].type" class="input-small">
<option value="MAI" fax>Main</option>
<option value="MOB" fax>Mobile</option>
<option value="FAX" fax>Fax</option>
<option value="CUS" fax>Custom</option>
</select>
...
これは、ある場所では大文字で出力され、別の場所では小文字で出力されるのは奇妙に見えます。そのため、その後、次のように文字列値を直接比較するだけでした。
...
<span>Selected type: @field("type").value</span>
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null && "FAX".equals(field("type").value)) { selected }>@text</option>
}
</select>
ここではまだ運がありません。いずれにせよ、現在の値 (この場合は「FAX」) がコンボ ボックスで選択されるように、目的の結果を達成する方法がまだわかりません。それを行う方法を提案できますか、それとも他の代替アプローチがありますか?
どんな助けでも大歓迎です。ありがとうございました。
UPDATE 2013-11-06 - 私のために働く解決策を見つけました:
Play のソース ツリーで scala/views/helper ファイルをブラウジングした後、inputRadioGroup.scala.html で見つけた if ステートメントを試してみました。
そこで、テンプレートの if ステートメントを次のように変更しました。
<select id="@field("type").id" name="@field("type").name" class="input-small">
@for((value, text) <- models.PhoneType.options) {
<option value="@value"
@if(field("type").value != null && Some(value) == (field("type").value)){ selected }>@text</option>
}
</select>
したがって、Some(value)を使用すると問題が修正され、現在のオプションがコンボボックスで選択されるようになりました。それが何を意味するのかよくわかりません。テンプレートをよりよく理解するには、おそらく少し Scala を学ぶ必要がありますが、うまくいきます。