こちらの続き
レイアウトがうまくいかなかったため、
試行錯誤した結果をメモします。
エラーメッセージをまとめて一つのマークアップにではなく、
入力項目ごとに出力したくなり、
ComponentFeedbackMessageFilter
を使用することでうまくいきました。
目次
実装後のスクリーンショット
以下のように表示されます。
ComponentFeedbackMessageFilterについて
12 Wicket forms in detail 6.x に記載がありますが、
IFeedbackMessageFilter
の実装クラスです。
実装クラスは3つあり、それぞれメッセージの出力単位が異なります。
-
ComponentFeedbackMessageFilter
コンポーネントごと -
ContainerFeedbackMessageFilter
コンテナーごと -
ErrorLevelFeedbackMessageFilter
エラーレベルごと
何故か、ComponentFeedbackMessageFilter
を使用した ComponentFeedbackPanelがあり、
他2つのFilter
使ったPanel
はないのですが、
これはよく使うからっていうことだと理解しました。
HTML
HTML
は以下の通り、修正しました。
input
項目ごとに、<div wicket:id="nameFeedback"></div>
といった形で、FeedbackPanelの挿入ポイントを追加しました。
<form role="form" wicket:id="mailForm">
<div class="form-group has-feedback" wicket:id="sendMessageFeedback"></div>
<div class="form-group has-feedback">
<input wicket:id="name" type="text" class="form-control" id="inputName" placeholder="Name" required>
<div wicket:id="nameFeedback"></div>
</div>
<div class="form-group has-feedback">
<input wicket:id="eMail" type="text" class="form-control" id="inputEmail" placeholder="Email" required>
<div wicket:id="eMailFeedback"></div>
</div>
<div class="form-group has-feedback">
<input wicket:id="subject" type="text" class="form-control" id="inputSubject" placeholder="Subject" required>
<div wicket:id="subjectFeedback"></div>
</div>
<div class="form-group has-feedback">
<textarea wicket:id="message" name="message" class="form-control" rows="3" placeholder="Message" required></textarea>
<div wicket:id="messageFeedback"></div>
</div>
<div class="form-group">
<button type="submit" wicket:id="sendMessage" class="btn btn-theme btn-lg btn-block">Send message</button>
</div>
</form>
FORM
// newMailForm
private Form newMailForm() {
Form form = new Form("mailForm") {
private static final long serialVersionUID = 5538299138211283825L;
public void onInitialize() {
super.onInitialize();
// name
TextField name = new RequiredTextField("name", Model.of(""));
name.setLabel(Model.of(getString("nameLabelText")));
name.add(StringValidator.maximumLength(150));
add(name);
FeedbackPanel nameFeedback = new AppFeedbackPanel("nameFeedback", name);
add(nameFeedback);
// eMail
TextField eMail = new RequiredTextField("eMail", Model.of(""));
eMail.setLabel(Model.of(getString("eMailLabelText")));
eMail.add(StringValidator.maximumLength(150));
eMail.add(EmailAddressValidator.getInstance());
add(eMail);
FeedbackPanel eMailFeedback = new AppFeedbackPanel("eMailFeedback", eMail);
add(eMailFeedback);
// subject
TextField subject = new RequiredTextField("subject", Model.of(""));
subject.setLabel(Model.of(getString("subjectLabelText")));
subject.add(StringValidator.maximumLength(150));
add(subject);
FeedbackPanel subjectFeedback = new AppFeedbackPanel("subjectFeedback", subject);
add(subjectFeedback);
// message
TextArea<String> message = new TextArea<>("message", Model.of(""));
message.setLabel(Model.of(getString("messageLabelText")));
message.setRequired(true);
message.add(StringValidator.maximumLength(10000));
add(message);
FeedbackPanel messageFeedback = new AppFeedbackPanel("messageFeedback", message);
add(messageFeedback);
AjaxButton sendMessage = new AjaxButton("sendMessage", Model.of(getString("messageButtonLabelText"))) {
private static final long serialVersionUID = -8204140666393922700L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
// --------------------------------------------------
// メール送信要求の登録処理.....
// getDefaultModelObjectAsString()で値を取得して、
// INSERT文なりを実行する。
// form.get("name").getDefaultModelObjectAsString();
// form.get("eMail").getDefaultModelObjectAsString();
// form.get("subject").getDefaultModelObjectAsString();
// form.get("message").getDefaultModelObjectAsString();
// ----------------------------------
// Formに対してのオペレーション
// super.onSubmit(target, form); 空メソッドなので、呼ばなくてOK
success(getString("messageMailSendSucceed"));
target.add(form);
}
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
// super.onError(target, form); 空メソッドなので、呼ばなくてOK
error(getString("messageMailSendError"));
target.add(form);
}
};
add(sendMessage);
setDefaultButton(sendMessage);
FeedbackPanel sendMessageFeedback = new AppFeedbackPanel("sendMessageFeedback", sendMessage);
add(sendMessageFeedback);
add(new AjaxFormValidatingBehavior("blur", Duration.ONE_SECOND));
}
};
return form;
}
説明
- 各
input
フィールドのコンポーネント元に、AppFeedbackPanel
を生成して、Form
にadd
します。
コンポーネントがそれぞれフィルターとして機能します。
FeedbackPanel nameFeedback = new AppFeedbackPanel("nameFeedback", name);
add(nameFeedback);
-
AjaxRequestTarget#add()
の引数にForm
を設定します。
これで、Form
配下のコンポーネント(FeedbackPanel
) にエラーメッセージが伝播します。
便利です。 -
add(new AjaxFormValidatingBehavior("blur", Duration.ONE_SECOND));
で、
onblur
の1秒後、(フォーカスを失って1秒後) に、Validation
を実行するようにしています。
これも便利です。 -
form.get("name").getDefaultModelObjectAsString()
で、Value取得が冗長なので、
CompoundPropertyModel
を使用する形で記述したほうが良いかもしれません。
AppFeedbackPanel
FeedbackPanel
を継承したクラスを作成しました。
作成理由は、デフォルトだと、<ul>
、<li>
タグを使う形の実装になっていて、
タグを変えたかったからです。
import org.apache.wicket.Component;
import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
import org.apache.wicket.feedback.ErrorLevelFeedbackMessageFilter;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.feedback.IFeedbackMessageFilter;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
/**
* AppFeedbackPanel
*
* @author Kem
*/
public class AppFeedbackPanel extends FeedbackPanel {
private static final long serialVersionUID = 8451969894945021514L;
/**
* Constructor
*
* @param id
*/
public AppFeedbackPanel(String id) {
super(id);
setOutputMarkupId(true);
}
/**
* Constructor
*
* @param id
* @param filter
*/
public AppFeedbackPanel(final String id, IFeedbackMessageFilter filter) {
super(id, filter);
setOutputMarkupId(true);
}
/**
* Constructor
*
* @param id
* @param compornent
*/
public AppFeedbackPanel(String id, Component compornent) {
this(id, new ComponentFeedbackMessageFilter(compornent));
}
/**
* Constructor
*
* @param id
* @param errorLevel
*/
public AppFeedbackPanel(String id, int errorLevel) {
this(id, new ErrorLevelFeedbackMessageFilter(errorLevel));
}
/**
* getCSSClass
*
* @param message
* @return
*/
@Override
protected String getCSSClass(final FeedbackMessage message) {
String cssClass;
switch (message.getLevel()) {
case FeedbackMessage.UNDEFINED:
cssClass = getString(FeedbackMessage.UNDEFINED_CSS_CLASS_KEY);
break;
case FeedbackMessage.DEBUG:
// FeedbackMessage.INFO 以下は、"alert alert-info"
cssClass = "alert alert-info";
break;
case FeedbackMessage.INFO:
cssClass = "alert alert-info";
break;
case FeedbackMessage.SUCCESS:
cssClass = "alert alert-success";
break;
case FeedbackMessage.WARNING:
cssClass = "alert alert-warning";
break;
case FeedbackMessage.ERROR:
cssClass = "alert alert-danger";
break;
case FeedbackMessage.FATAL:
// FeedbackMessage.ERROR 以上は、"alert alert-danger"
cssClass = "alert alert-danger";
break;
default:
cssClass = "feedbackPanel" + message.getLevelAsString();
}
return cssClass;
}
}
HTMLは以下の通りです。feedbackul
がul
なのは、
継承元のFeedbackPanel
の実装都合となります。
<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
<div wicket:id="feedbackul">
<div wicket:id="messages">
<span wicket:id="message">A message</span>
</div>
</div>
</wicket:panel>
</body>
</html>
参考
以下参考に、FORM
、FeedbackPanel
は作成しました。
-
Wicket Client Side Validation – [codecrate]
メソッドAjaxFormValidatingBehavior#addToAllFormComponents()
はWicket 7
で削除されました。 -
pm-wicket-utils/BootstrapFeedbackPanel.java
IFeedbackMessageFilter
実装の参考にしました。
使用機会は今のところなかったですが、AndComposedFeedbackMessageFilter
、ExcludePopoverMessageFilter
などの実装があります。
以上です。
コメント