Eclipse+JSF+JPAで作るアプリ(20)―Primefaces ドラッグ&ドロップ
今回は、カート画面でのドラッグ&ドロップです。
借りたい映画のエリアと、カートに戻す映画のエリア2つの領域をドラッグ&ドロップで移動させます。
先に画面を見せます。
- ドラッグすると、ドロップできるエリアがハイライトされ、このテーマでは薄い青色になります。
- ドラッグもドロップもしていないと、ハイライトは戻り、薄い灰色になります。
画像は英語版Wikipediaのポスター画像から借用しています。
それでは実際のソースを見ていきます。
xhtmlでのドラッグ&ドロップの定義
cart.xhtmlで定義しています。
先に全体を載せ、細かいパーツごとの説明は後に行います。
<h:form id="movieCartForm"> <p:fieldset id="cartField" legend="カートの中の映画"> <p:outputPanel id="cartPanel"> <h:outputText value="カートに戻す映画をドロップしてください。" rendered="#{empty movieCartView.moviesInCart}" style="font-size:24px;" /> <p:dataGrid id="cartGrid" var="movie" value="#{movieCartView.moviesInCart}" columns="5" rendered="#{not empty movieCartView.moviesInCart}"> <p:panel id="cartPnl" header="#{movie.title}" style="text-align:center"> <h:panelGrid columns="1"> <p:graphicImage url="./resource/image/#{movie.image}"/> </h:panelGrid> </p:panel> <p:draggable for="cartPnl" revert="true" handle=".ui-panel-titlebar" stack=".ui-panel" /> </p:dataGrid> </p:outputPanel> </p:fieldset> <p:fieldset id="rentField" legend="借りる映画"> <p:outputPanel id="rentPanel"> <h:outputText value="借りたい映画をドロップしてください。" rendered="#{empty movieCartView.moviesToBeLent}" style="font-size:24px;" /> <p:dataGrid id="rentGrid" var="movie" value="#{movieCartView.moviesToBeLent}" columns="3" rendered="#{not empty movieCartView.moviesToBeLent}"> <p:panel id="rentPnl" header="#{movie.title}" style="text-align:center"> <h:panelGrid columns="1"> <p:graphicImage url="./resource/image/#{movie.image}"/> </h:panelGrid> </p:panel> <p:draggable for="rentPnl" revert="true" handle=".ui-panel-titlebar" stack=".ui-panel" /> </p:dataGrid> </p:outputPanel> </p:fieldset> <p:droppable for="rentField" tolerance="touch" activeStyleClass="ui-state-highlight" datasource="cartGrid"> <p:ajax listener="#{movieCartView.onDropToRent}" update="cartPanel rentPanel" /> </p:droppable> <p:droppable for="cartField" tolerance="touch" activeStyleClass="ui-state-highlight" datasource="rentGrid"> <p:ajax listener="#{movieCartView.onDropToCart}" update="cartPanel rentPanel" /> </p:droppable> <h:panelGrid columns="2"> <p:commandButton id="rent" value="映画を借りる" action="#{movieCartView.rentMovies}" update="@form"/> <p:commandButton id="back" value="戻る" action="#{movieCartView.back}" update="@form"/> </h:panelGrid> <p:messages /> </h:form>
ドロップを促すガイド
<h:outputText value="カートに戻す映画をドロップしてください。" rendered="#{empty movieCartView.moviesInCart}" style="font-size:24px;" />
- 通常のWebアプリケーションでドラッグ&ドロップできるとは考えないので出したほうがよいでしょう。
- renderedアトリビュートでリストが空のときだけ表示するようにします。
draggableタグ
<p:draggable for="cartPnl" revert="true" handle=".ui-panel-titlebar" stack=".ui-panel" />
droppableタグ
<p:droppable for="rentField" tolerance="touch" activeStyleClass="ui-state-highlight" datasource="cartGrid"> <p:ajax listener="#{movieCartView.onDropToRent}" update="cartPanel rentPanel" /> </p:droppable>
javaソース内でのハンドル
Primefaces Showcaseのドラッグ&ドロップは、1つの領域のサンプルしかありませんが、
この例では、2つの領域があります。そのため、ドロップイベントで
- 自分の領域から出て、自分の領域に戻る
という個所をハンドルする必要があります。
public void onDropToRent(DragDropEvent ddEvent) { Movie movie = ((Movie) ddEvent.getData()); if (ddEvent.getDragId().startsWith("movieCartForm:cartGrid") && "movieCartForm:cartField".equals(ddEvent.getDropId())) return; if (ddEvent.getDragId().startsWith("movieCartForm:rentGrid") && "movieCartForm:rentField".equals(ddEvent.getDropId())) return; if (!moviesToBeLent.contains(movie)) { moviesToBeLent.add(movie); moviesInCart.remove(movie); } } public void onDropToCart(DragDropEvent ddEvent) { Movie movie = ((Movie) ddEvent.getData()); if (ddEvent.getDragId().startsWith("movieCartForm:cartGrid") && "movieCartForm:cartField".equals(ddEvent.getDropId())) return; if (ddEvent.getDragId().startsWith("movieCartForm:rentGrid") && "movieCartForm:rentField".equals(ddEvent.getDropId())) return; if (!moviesInCart.contains(movie)) { moviesInCart.add(movie); moviesToBeLent.remove(movie); } }
- droppableタグ内のajaxタグで指定したメソッドには、引数DragDropEventが渡されます。
- DragDropEventの、getDragId()と、getDropId()というAPIで、ウジッドのIDを取得できますので、これで、どのコントロールから出てきて、どのコントロールに落とされているかを判別することができます。
- この例では、同じ領域に落とされている場合は、何もしないでreturnするようにしてあります。
以上です。
リッチコンポーネントを使えば、このように比較的簡単にドラッグ&ドロップを実装できます。