Eclipse+JSF+JPAで作るアプリ(14)―Primefaces データテーブルの設定 後半(1) イベントハンドル
Primefacesのデータテーブルタグ(p:datatable)の設定を色々と変えて動作を確認を行うセッションの後半です。
- 選択時のイベントハンドルを行う。
- コンテキストメニューを表示する。
- セルをグリッドで編集できるようにする。
を行えるようにします。
前回までで、管理者がユーザの追加ができるようになったので、削除ができるようにします。
また、パスワードは非表示なので、コンテキストメニューから初期化できるようにします。
編集はグリッドで行えるよう実装することで、CRUD操作は一通り完成です。
さまざまなコントロールや実装方法を試したいため、敢えてこうしています。
後半その1は、選択時のイベントハンドルです。
削除ボタンの実装
画面→アクション→ロジックの順で実装していきます。
userlist.xhtml アクションに、editUserView.removeUserというメソッドを指定します。
<h:form id="userListForm"> <p:commandButton id="removeButton" value="選択したユーザを削除" ajax="true" action="#{editUserView.removeUser}" update=":userListForm"> </p:commandButton> <br/> <!--隙間を開けるための改行--> <br/> …
EditUserView.java removeUserメソッドを実装します。
EditUserViewクラスのselectedUsersフィールドは、Primefacesのp:datatableがチェックしたものを自動でセットしてくれます。
public String removeUser() { if( selectedUsers == null || selectedUsers.isEmpty() ) return "success"; UserManager.removeUser(selectedUsers); users.removeAll(selectedUsers); userModel.setWrappedData(users); ViewUtil.AddMessage("ユーザの削除", selectedUsers.size()+"件のユーザを削除しました。"); return "success"; }
- usersは、表示しているユーザ一覧のフィールドです。選択されたユーザをremoveAllで引いています。
- userModel(SelectableDataModelを継承したクラスのインスタンス)のsetWrappedDataで、削除したusersをセットしています。
UserManager.javaに、removeUserを実装します。
public static int removeUser( List<User> users ) { EntityManager em = getEm(); EntityTransaction tx = em.getTransaction(); tx.begin(); int removeCount = 0; for (User user : users) { User find = em.find(User.class, user.getId()); if( find == null ) continue; List<LendHistory> histories = find.getLendHistories(); for (LendHistory history : histories) { history.setLendUser(null);//履歴からは、ユーザをnullにしてから削除する。 em.merge(history);//履歴の更新 } em.remove(find); removeCount++; } tx.commit(); em.close(); return removeCount; }
画面は以下のようになります。
ご覧のように、選択されていないのにボタンが有効になっています。
これをチェックボックスをイベントハンドルして、ユーザが選択されていないときは、無効にするよう実装します。
データテーブルのイベントハンドラの実装
p:datatableタグにdisabled="#{empty editUserView.selectedUsers}"を付ければ無効にできそうですが、イベントが拾えていません。
userlist.xml イベントが拾えないため、disabledにできない。
<p:commandButton id="removeButton" value="選択したユーザを削除" ajax="true" disabled="#{empty editUserView.selectedUsers}" action="#{editUserView.removeUser}" update=":userListForm">
userlist.xml ボタンの無効化に、editUserViewのisSelectedプロパティで判別するようにしたもの。
7/31 追記:isSelectedを作成しなくても、disabled="#{empty editUserView.selectedUsers}"のまま、 下記のajaxタブで、listenerなしで、ただ単にupdate=":userListForm:removeButton"と するだけでボタンの有効化、無効化の制御はできます。
<p:commandButton id="removeButton" value="選択したユーザを削除" action="#{editUserView.removeUser}" update=":userListForm" disabled="#{false == editUserView.isSelected}"> </p:commandButton>
- disabledに、isSelected == false条件を指定。
userlist.xml p:ajaxタグで、チェックボックスのイベントハンドラを呼び出すよう指定したもの。
<p:dataTable id="userList" value="#{editUserView.userModel}" var="user" selection="#{editUserView.selectedUsers}" rowKey="#{user.id}" paginator="true" paginatorPosition="top" rows="10" rowsPerPageTemplate="5,10,15,30,50" sortMode="multiple" sticy="true" > <p:ajax event="rowSelect" listener="#{editUserView.handleSelect}" update=":userListForm:removeButton" /> <p:ajax event="rowUnselect" listener="#{editUserView.handleUnselect}" update=":userListForm:removeButton" /> <p:ajax event="rowSelectCheckbox" listener="#{editUserView.handleSelect}" update=":userListForm:removeButton" /> <p:ajax event="rowUnselectCheckbox" listener="#{editUserView.handleUnselect}" update=":userListForm:removeButton" /> <p:ajax event="toggleSelect" listener="#{editUserView.handleToggleSelect}" update=":userListForm:removeButton" />
- eventには、rowSelect,rowUnselect,rowSelectCheckbox,rowUnselectCheckbox,toggleSelectを指定しています。
- toggleSelectは、全体(ヘッダーのチェックボックス)を選択した際に呼ばれます。
//@Getter lombokのgetterは、isSelected()となり、JSFの命名規則getIsSelectedに合わないため使えない。 private boolean isSelected; public boolean getIsSelected() { return isSelected; } public void handleSelect( SelectEvent event) { isSelected = (getSelectedUsers().size() > 0); } public void handleUnselect( UnselectEvent event) { isSelected = (getSelectedUsers().size() > 0); } public void handleToggleSelect( ToggleSelectEvent event) { isSelected = (getSelectedUsers().size() > 0); }
- イベントハンドラには、SelectEvent, UnselectEvent, ToggleSelectEventが引数で渡されます。
- http://www.primefaces.org/showcase/ui/data/datatable/selection.xhtml の、SelectionView.javaに実装例もあります。
EditUserView.javaのremoveUserの更新。
public String removeUser() { if( selectedUsers == null || selectedUsers.isEmpty() ) return "success"; UserManager.removeUser(selectedUsers); users.removeAll(selectedUsers); userModel.setWrappedData(users); ViewUtil.AddMessage("ユーザの削除", selectedUsers.size()+"件のユーザを削除しました。"); isSelected = false;//削除後はボタンを無効にする。 return "success"; }
- 削除した際にボタンを無効にするため、忘れずに isSelected=false を設定しましょう。
未選択→無効 1つ選択→有効 トグルで選択→有効となっています。
現状、削除ボタンを押すと、即座に削除されてしまうため、確認ダイアログを出すようにしたいです。
確認ダイアログの出し方。
p:confirmDialogというタグをp:commandButtonのタグ内で使います。
<p:commandButton id="removeButton" value="選択したユーザを削除" action="#{editUserView.removeUser}" update=":userListForm" disabled="#{false == editUserView.isSelected}"> <p:confirm header="確認" message="選択したユーザを削除しますか?" icon="ui-icon-info" /> <p:confirmDialog global="true" showEffect="explode" hideEffect="slide"> <p:commandButton value="はい" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" /> <p:commandButton value="いいえ" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" /> </p:confirmDialog> </p:commandButton>
- 複合コンポーネントを使っています。
- showEffect, hideEffectを設定することでダイアログ表示がアニメーションします。
- http://www.primefaces.org/showcase/ui/overlay/confirmDialog.xhtml に「Destory the world」というボタンの例があります。システムエラーで世界を破滅できませんでした。
左:確認ダイアログの表示(背景もグレーアウトします) 右:エフェクト中のもの。explodeは爆発エフェクトです。
長くなりましたので、後半(2)に続きます。