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;
	}
  • 以前作ったremoveUserは1ユーザしか削除できなかったため、リストで消せるよう修正しました。
  • CDIを使っていないため、トランザクション管理を自分でしていて長くなっています。

画面は以下のようになります。
f:id:tshix:20150729224039p:plain
ご覧のように、選択されていないのにボタンが有効になっています。
これをチェックボックスをイベントハンドルして、ユーザが選択されていないときは、無効にするよう実装します。

データテーブルのイベントハンドラの実装

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は、全体(ヘッダーのチェックボックス)を選択した際に呼ばれます。


EditUserView.java イベントハンドラの実装

	//@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);
	}


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つ選択→有効 トグルで選択→有効となっています。
f:id:tshix:20150729233409p:plainf:id:tshix:20150729233421p:plainf:id:tshix:20150729233427p:plain

現状、削除ボタンを押すと、即座に削除されてしまうため、確認ダイアログを出すようにしたいです。

確認ダイアログの出し方。

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>

左:確認ダイアログの表示(背景もグレーアウトします) 右:エフェクト中のもの。explodeは爆発エフェクトです。
f:id:tshix:20150729235338p:plainf:id:tshix:20150729235344p:plain


長くなりましたので、後半(2)に続きます。