の続きと言うか、ついでに。
やりたいこと
エラーメッセージを入力領域にツールチップを出力する
やりかた
xhtmlのinput要素のtitleにエラーメッセージを出力する
前回の記事と ほぼ同じ発想です。
実装
Titleに出力メッセージを扱うクラス
BeanValidationExceptionのInterceptorで
をマージして、Titleに出力するメッセージ用のクラスを編集します。
@Action @Interceptor @Priority(Interceptor.Priority.APPLICATION) @Dependent public class BeanValidationExceptionInterceptor { private final CurrentViewContext context; private final MessageConverter messageConverter; private final MessageWriter messageWriter; private final ClientComplementManager clientComplementManager; private final ErrorStyle errorStyle; private final ErrorTooltip errorTooltip; @Inject public BeanValidationExceptionInterceptor(CurrentViewContext context, MessageConverter messageConverter, MessageWriter messageWriter, ClientComplementManager clientComplementManager, ErrorStyle errorStyle, ErrorTooltip errorTooltip) { this.context = context; this.messageConverter = messageConverter; this.messageWriter = messageWriter; this.clientComplementManager = clientComplementManager; this.errorStyle = errorStyle; this.errorTooltip = errorTooltip; } @AroundInvoke public Object invoke(InvocationContext ic) throws Exception { String currentViewId = context.currentViewId(); try { return ic.proceed(); } catch (BeanValidationException ex) { ClientIdsWithComponents clientIdsWithInputComponents = new InputComponentScanner().scan(); ClientIdMessages clientidMessages = messageConverter.toClientIdMessages(ex.getValidatedResults(), ic.getTarget().getClass().getSuperclass(), clientIdsWithInputComponents); ClientIdsWithComponents clientIdsWithHtmlMessages = new HtmlMessageScanner().scan(); messageWriter.appendErrorMessageToComponent(clientidMessages.toClientIdMessagesForWriting(clientIdsWithHtmlMessages)); FacesContext.getCurrentInstance().validationFailed(); clientComplementManager.setClientidMessages(clientidMessages); this.errorStyle.set(clientIdsWithInputComponents, clientidMessages); //ツールチップ用のインスタンスに情報を渡します this.errorTooltip.set(clientIdsWithInputComponents, clientidMessages); return currentViewId; } } }
情報を保持するクラス
@Named @RequestScoped public class ErrorTooltip { private ClientIdsWithComponents clientIdsWithComponents; private ClientIdMessages clientIdMessages; @PostConstruct private void init() { this.clientIdsWithComponents = new ClientIdsWithComponents(); this.clientIdMessages = new ClientIdMessages(); } public void set(ClientIdsWithComponents clientIdsWithInputComponents, ClientIdMessages clientIdMessages) { Set<String> clientIds = clientIdMessages.getList().stream() .map(ClientIdMessage::getClientId) .collect(Collectors.toSet()); this.clientIdsWithComponents = clientIdsWithInputComponents.filter(clientIds); this.clientIdMessages = clientIdMessages; } /** * 指定したIDの項目が検証不正だった場合に適用する メッセージ を返却します. * <P> * xhtmlでのパラメータ指定時には、シングルクウォートで値を指定してください. * * @param id 対象となるコンポーネントのID(JSFのクライアントIDではありません) * @return 当該項目IDにエラーがない場合は 空文字を返却します. */ public String byId(String id) { String clientId = this.clientIdsWithComponents.getOrNull(id); if (clientId == null) { return ""; } return clientIdMessages.getMessage(clientId); } /** * 指定したClientId(フルパス)の項目が検証不正だった場合に適用する メッセージ を返却します. * * @param clientId 対象となるコンポーネントのID(JSFのクライアントIDではありません) * @return 当該項目IDにエラーがない場合は 空文字を返却します. */ public String byClientId(String clientId) { return clientIdMessages.getMessage(clientId); } }
xhtmlの記述
画面IDとクライアントID、いずれからでもメッセージを取得するメソッドを準備していますが、input要素に直接出力するので 通常は クライアントIDをパラメータとするメソッドを 使うことになると思います。
引数はcomponent.clientId
を使えば、当該コンポーネントのクライアントIDが取得できます。
<div class="field"> <label>利用者ID</label> <input jsf:styleClass="short-input" type="text" placeholder="someone@example.com" jsf:id="email" jsf:value="#{userRegistrationPage.email}" title="#{errorTooltip.byClientId(component.clientId)}"/> </div>
Code
vermeer_etc / jsf-ddd / source / — Bitbucket
さいご
まだ繰り返し領域に関する制御は保留だけど
とりあえず、これで メッセージ関連は一段落かな?