PrimeFaces の DataTable で paginator と binding を一緒に使うと…
メモ:PF DataTable でページングと binding を一緒に使った時に問題が出る。
画面イメージとか貼った方が分かりやすそうですが、面倒なんで用意してません。
バージョンは PrimeFaces 5.2 です。
コードはこんなの。
PrimeFaces の DataTable で paginator と binding を指定しています。
また、行には commandLink を置いてそこで次の画面に遷移さす感じ。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:scmui="http://jp.co.scm-net/jsf/components"> <h:head> <f:facet name="first"> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta charset="UTF-8" /> </f:facet> <title>Binding</title> </h:head> <h:body> <h:form id="form"> <h1>Primefaces DataTable paginator + binding デモ</h1> <h2>いきなり1ページ目のリンクを押すと、何故か2度押しされた感じになる?(但し、2回目はViewScopedなBeanのpostConstructも呼ばれる)</h2> <p:dataTable binding="#{dataTableBean.dataTable}" paginator="true" rows="2" value="#{dataTableBean.details}" var="item"> <p:column headerText="name"><h:outputText value="#{item.name}"/></p:column> <p:column headerText="link"><p:commandLink value="リンク" action="#{dataTableBean.jump}" ajax="false"/> </p:column> </p:dataTable> </h:form> </h:body> </html>
Java 側は大したことないコード。
遷移先の nextView.xhtml は空でもOK。
package sample; import java.io.Serializable; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.faces.view.ViewScoped; import javax.inject.Inject; import javax.inject.Named; import org.primefaces.component.datatable.DataTable; @Named @ViewScoped public class DataTableBean implements Serializable { private static final long serialVersionUID = 1L; static final Logger logger = Logger.getLogger(DataTableBean.class.getName()); private DataTable dataTable; public DataTable getDataTable() { return dataTable; } public void setDataTable(DataTable dataTable) { this.dataTable = dataTable; } private List<DetailBean> details; public List<DetailBean> getDetails() { return details; } @PostConstruct void postConstruct() { logger.info("DataTableBean#postConstruct : " + this.hashCode()); details = Arrays.asList(new DetailBean("aaa"), new DetailBean("bbb"), new DetailBean("ccc")); } public String jump() { logger.info("DataTableBean#jump : " + this.hashCode()); return "nextView"; } } public class DetailBean implements Serializable { private static final long serialVersionUID = 1L; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public DetailBean() {} public DetailBean(String name) { this.name = name; } }
paginator と binding を使ってる以外は、ありふれた明細からリンクな感じのコードです。
で、何が起きるかというと DataTable にデータが表示された直後に 1ページ目の何れかの行の CommandLink/Button を押すと、何故か2回 action/actionListener が走ってしまいます。
action で画面遷移 + ViewScoped な Baking Bean の場合は、postConstruct も走ります。
他のページのリンクは大丈夫です。また、他のページに移動してから1ページ目に戻っても起きません。
もっというと、同じ画面に CommandLink/Button が別にあり、それをclickしてからなら1ページ目でも起きません。
要はCommandLink/Button の最初のリクエストがDataTable内のリンク/ボタンならダメな感じ。
CommandLink/Button と書いたのは、DataTable外の inputText の ajax を走らせてからでも現象が発生したからです。
ちなみに dataTable の binding を外した場合は、最初のリクエストが DataTable 内の リンク/ボタンでも大丈夫でした。
また、paginator を使っていない場合も大丈夫です。
paginator と binding 両方使ってる時だけ起きるようです。
ガッツが足りないのでソースは追っかけてませんが、ページングを使う場合はなるべく binding を使わない方が良さそうです。
そもそも binding 自体あまり使わないかもしれませんが。。
サンプルコード全体はこちら
OdaShinsuke/DataTablePaginator · GitHub
再検索した時に1ページ目に戻したいとかも、binding を使わずに FacesContext から直接取るか、
JavaScript で
PF('widgetTable').getPaginator().setPage(0);
でやる方法もあります。
http://forum.primefaces.org/ にはうまく説明出来そうにないので投げてません。