{"id":24,"date":"2008-10-02T23:13:03","date_gmt":"2008-10-03T04:13:03","guid":{"rendered":"http:\/\/www.andygibson.net\/blog\/?p=24"},"modified":"2010-07-26T21:19:05","modified_gmt":"2010-07-27T02:19:05","slug":"codeless-ajax-ordered-and-paginated-tables-in-seam","status":"publish","type":"post","link":"https:\/\/www.andygibson.net\/blog\/tutorial\/codeless-ajax-ordered-and-paginated-tables-in-seam\/","title":{"rendered":"Codeless Ajax Ordered and Paginated Tables in Seam"},"content":{"rendered":"<p>(<b>Update<\/b> : fixed some of the missing images)<\/p>\n<p>One common code pattern that we find ourselves writing time and again is the ability to display tables which are paginated and sortable. Ideally, this is something we should try and be able to re-use throughout our application.<\/p>\n<h2>Current Situation<\/h2>\n<p>Let&#8217;s start by looking at where we are now with the features that come with Seam out of the box. In particular, we will be looking at the <code class=\"code\">dataScroller<\/code> component and the <code class=\"code\">EntityQuery<\/code> object.<!--more--><\/p>\n<h2>Data Scroller Problems<\/h2>\n<p>Richfaces, included with Seam, offers a data paginator which can be used with a standard JSF <code class=\"code\">dataTable<\/code> to paginate the source data of the <code class=\"code\">dataTable<\/code>. It<br \/>\n    does this by taking the number of items in the source list and determining how many pages are needed to display the data. The problem with this is that it requires that all objects in the source list be represented as an object, even if it is just a memento or placeholder for the real entity. This is because the <code>dataScroller<\/code> has no sense of queries or JPA models to fetch the number of items in the list. Obviously, this can be problematic when you have thousands of items in the list. Not only does it take up precious memory resources, but it takes quite a lot of time to load the objects from the database. Even a placeholder or memento requires data from the database which<br \/>\ntakes time and resources to iterate through,read and store.<\/p>\n<p>There are also times when we needlessly load the list of objects for no reason other than the user went to a page to look at some unrelated data. Consider an address book where you view a clients details and it contains a table listing the phone calls made to the client. There could be hundreds of records, all of which are loaded because we are using the dataScroller that requires all items to be loaded. After they have all been loaded, and the page is finally displayed to the user, the user only wanted to look at the clients birthdate making the fetching redundant. For this reason, if we are going to load the data, we should do it as quickly as possible since it may not even be looked at and the user will be waiting unnecessarily.<\/p>\n<p>Typically, if we have a thousand records, the chances of the user looking through all of them is low. They may just want to see the last 10 phone calls made to the client or the last time the client was called. In this case, again, we don&#8217;t want to load all the objects, we want to bring the page back to the user quickly, and then let them sort by whatever criteria they choose to get to the data they want.<\/p>\n<h2>Sorting Data<\/h2>\n<p>With the standard <code class=\"code\">dataTable<\/code>, or with any HTML table, we have no way of sorting the data automatically. We don&#8217;t really want to load all the data down to the client and use javascript for the same reasons we don&#8217;t want to use a paginator that requires all the data be loaded.<\/p>\n<p>Both our problems, pagination and ordering, stems from the fact that we do not have a standard server side object interface by which these &#8216;dumb&#8217; html component can go against in order to manipulate the data as necessary.<\/p>\n<h2>EntityQuery Problems<\/h2>\n<p>The Seam team wrote the <code class=\"code\">EntityQuery<\/code> component as a generic query object which was also EL aware. It includes attributes for handling where clauses, pagination, and ordering as well as a method for obtaining the number of results in the query. The Seam documentation describes ways of using the <code  class=\"code\">EntityQuery<\/code> to provide pagination using parameters which can get messy. This is especially so when we have multiple queries on a page, for example in our address book, we not only list the most recent calls to a client, but on another tab, we have a list of recent orders for the client.<\/p>\n<p>Another problem with the current entity query is that it cannot be used in <code class=\"code\">PAGE<\/code> scope, which means that if you want to maintain state from one request to the next, you need to either start a conversation or pass parameters around. Again, this is something we should seek to fix in our solution to avoid having to start conversations unnecessarily or waste time setting up parameters.<\/p>\n<p>In order to achieve our goals, we will define two facelets that can be re-used, one for the sortable column, and the other for the pagination. These facelets provides the mechanism by which the JSF controls interact with the well defined interface on the <code class=\"code\">EntityQuery<\/code>.<\/p>\n<h2>Getting Started<\/h2>\n<p>Let&#8217;s start by examining our model, our basic query and our initial view html. We have a <code class=\"code\">Person<\/code> class that has an Id, a first and last name, and a numerical score.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n@Entity\r\n@Table(name=&quot;PEOPLE&quot;)\r\npublic class Person {\r\n        \r\n        @Id\r\n        @Column(name=&quot;ID&quot;)\r\n        private Long id;\r\n        \r\n        @Column(name=&quot;FIRST_NAME&quot;,length=24)\r\n        private String firstName;\r\n\r\n        @Column(name=&quot;LAST_NAME&quot;,length=24)\r\n        private String lastName;\r\n        \r\n        @Column(name=&quot;SCORE&quot;)\r\n        private Integer score;\r\n}\r\n\r\n<\/pre>\n<p>Typically, when we are building a list using Seam&#8217;s <code class=\"code\">EntityQuery<\/code>, we would subclass the <code class=\"code\">EntityQuery<\/code> and override our methods for our particular query, or set them in the constructor. Alternatively, we could set them up in <code class=\"code\">components.xml<\/code>.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n@Name(&quot;personQuery&quot;)\r\n@Scope(ScopeType.CONVERSATION)\r\npublic class PersonQueryBean extends EntityQuery&amp;lt;Person&amp;gt; {\r\n\r\n        public PersonQueryBean() {\r\n                setEjbql(&quot;select p from Person p&quot;);\r\n\r\n                setMaxResults(10);\r\n                setFirstResult(0);\r\n\r\n        }\r\n}\r\n<\/pre>\n<p>We can display this query in a JSF page with the following html.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;a:outputPanel id=&quot;renderPanel&quot;&gt;\r\n        &lt;h:dataTable value=&quot;#{personQuery.resultList}&quot; var=&quot;v_person&quot;        \r\n                styleClass=&quot;dataTable&quot; rowClasses=&quot;row1,row2&quot;                \r\n                headerClass=&quot;dataTableHeader&quot;&gt;\r\n                &lt;h:column&gt;\r\n                        &lt;f:facet name=&quot;header&quot;&gt;ID&lt;\/f:facet&gt;\r\n                        &lt;s:link value=&quot;#{v_person.id}&quot; view=&quot;\/personView.xhtml&quot;&gt;\r\n                                &lt;f:param name=&quot;personId&quot; value=&quot;#{v_person.id}&quot; \/&gt;\r\n                        &lt;\/s:link&gt;\r\n                &lt;\/h:column&gt;\r\n\r\n                &lt;h:column&gt;\r\n                        &lt;f:facet name=&quot;header&quot;&gt;First Name&lt;\/f:facet&gt;\r\n                        &lt;h:outputText value=&quot;#{v_person.firstName}&quot; \/&gt;\r\n                &lt;\/h:column&gt;\r\n\r\n                &lt;h:column&gt;\r\n                        &lt;f:facet name=&quot;header&quot;&gt;Last Name&lt;\/f:facet&gt;\r\n                        &lt;h:outputText value=&quot;#{v_person.lastName}&quot; \/&gt;\r\n                &lt;\/h:column&gt;\r\n\r\n                &lt;h:column&gt;\r\n                        &lt;f:facet name=&quot;header&quot;&gt;Score&lt;\/f:facet&gt;\r\n                        &lt;h:outputText value=&quot;#{v_person.score}&quot; \/&gt;\r\n                &lt;\/h:column&gt;\r\n\r\n        &lt;\/h:dataTable&gt;\r\n&lt;\/a:outputPanel&gt;\r\n<\/pre>\n<p>This gives us a list of people, where the maximum number of results is still constrained by the <code  class=\"code\">EntityQuery<\/code> to 10. This is how things are out of the box with Seam. The <code class=\"code\">outputPanel<\/code> tag is used by JSF to isolate updates to that panel only. This gives the user a smoother experience as they browse the results.<\/p>\n<p>This <code class=\"code\">EntityQuery<\/code> will become the standard interface with which our JSF will interact in order to change the order of the results, and the results page that is shown.<\/p>\n<p><img src=\"\/blog\/img\/personlist1.png\" \/><\/p>\n<h2>Improving Things<\/h2>\n<p>Let&#8217;s start by extending the <code class=\"code\">EntityQuery<\/code>. We need to abstract the original <code class=\"code\">orderBy<\/code> attribute of the <code class=\"code\">EntityQuery<\/code> in order to control and query our ordering status. The original <code class=\"code\">orderBy<\/code> attribute works by accepting the actual field names and the order direction. This can be cumbersome to work with, especially when trying to determine the current ordering and direction in the view. This is especially the case when your JSF page needs to work out whether the order is ascending or descending when the order is set to <code class=\"code\">p.firstName DESC, p.lastName DESC<\/code>. Also, with the current <code class=\"code\">orderBy<\/code> attribute, there is a risk of SQL injection since typically, the page is setting the value directly. Decoupling the view from the ordering logic in this case is a good<br \/>\npractice and also improves security.<\/p>\n<p>By having two values, an order key and a direction attribute, on the <code class=\"code\">EntityQuery<\/code> we can easily determine the active order and the direction. These order key values can be mapped to actual model fields to prevent injection and also makes it easier for order by clauses that use multiple fields, as well as decoupling the<br \/>\nordering logic from the view.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class ExtendedEntityQuery&amp;lt;E&amp;gt; extends EntityQuery&amp;lt;E&amp;gt; {\r\n\r\n        private String orderKey;\r\n        private boolean ascending;\r\n        private Map&amp;lt;String, String&amp;gt; orderKeyFieldMap = new HashMap&amp;lt;String, String&amp;gt;();\r\n\r\n        public String getOrderKey() {\r\n                return this.orderKey;\r\n        }\r\n\r\n        public void setOrderKey(String orderKey) {\r\n                \/\/ if this value is already the order key, we are just inverting the\r\n                \/\/ direction\r\n                if (orderKey != null &amp;&amp; orderKey.equals(this.orderKey)) {\r\n                        ascending = !ascending;\r\n                } else {\r\n                        \/\/ else we are setting a new order field, so reset the direction\r\n                        this.orderKey = orderKey;\r\n                        ascending = true;\r\n                }\r\n                \/\/ invalidate the results\r\n                refresh();\r\n        }\r\n\r\n        public void setAscending(boolean ascending) {\r\n                this.ascending = ascending;\r\n                \/\/ invalidate the results after changing the order direction\r\n                refresh();\r\n        }\r\n\r\n        public boolean getAscending() {\r\n                return this.ascending;\r\n        }\r\n\r\n        @Override\r\n        public String getOrder() {\t \r\n                \/\/ get the order fields from the key\r\n                String order = orderKeyFieldMap.get(orderKey);\r\n                \/\/ if not set, then there is no ordering\r\n                if (order == null) {\r\n                        return null;\r\n                }\r\n                \/\/ parse out fields and add order\r\n                String[] fields = order.split(&quot;,&quot;);\r\n                order = &quot;&quot;;\r\n                \/\/ concatenate the fields with the direction, put commas in between\r\n                for (String field : fields) {\r\n                        if (order.length() != 0) {\r\n                                order = order + &quot;, &quot;;\r\n                        }\r\n                        order = order + field + (ascending ? &quot; ASC &quot; : &quot; DESC &quot;);\r\n                }\r\n\r\n                return order;\r\n        }\r\n\r\n        public Map&amp;lt;String, String&amp;gt; getOrderKeyFieldMap() {\r\n                return orderKeyFieldMap;\r\n        }\r\n\r\n        public void setOrderKeyFieldMap(Map&amp;lt;String, String&amp;gt; orderKeyFieldMap) {\r\n                this.orderKeyFieldMap = orderKeyFieldMap;\r\n        }\r\n\r\n\r\n        \/**\r\n         * Calculates and returns the current page number based on the first result\r\n         * value\r\n         * \r\n         * @return The current page number\r\n         *\/\r\n        public int getActivePage() {\r\n                Integer fr = getFirstResult();\r\n                Integer mr = getMaxResults();\r\n                if (fr != null &amp;&amp; mr != null) {\r\n                        return 1 + (fr \/ mr);\r\n                }\r\n                return 0;\r\n        }\r\n\r\n}\r\n<\/pre>\n<p>This is essentially the bulk of our code since it builds on the existing <code class=\"code\">EntityQuery<\/code> class which implements the meat of our query. We added two new attributes <code class=\"code\">ascending<\/code> and <code class=\"code\">orderKey<\/code>. The <code class=\"code\">ascending<\/code> attribute indicates which direction the index is ordered in, and the <code class=\"code\">orderKey<\/code> is used to indicate how we want to order the results. We use the <code class=\"code\">orderKey<\/code> to lookup the actual fields to order by using the <code style=\"\">orderKeyFieldMap<\/code>. When initializing the query, we add the key\/field values to the map to use for lookups. We&#8217;ll modify our <code class=\"code\">PersonQuery<\/code> to extend from our <code class=\"code\">ExtendedEntityQuery<\/code>, and we add the key\/field pairs to the <code class=\"code\">orderKeyFieldMap<\/code>.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n@Name(&quot;personQuery&quot;)\r\n@Scope(ScopeType.CONVERSATION)\r\npublic class PersonQueryBean extends ExtendedEntityQuery&amp;lt;Person&amp;gt; {\r\n\r\n        public PersonQueryBean() {\r\n                setEjbql(&quot;select p from Person p&quot;);\r\n\r\n                setMaxResults(10);\r\n                setFirstResult(0);\r\n\r\n                getOrderKeyFieldMap().put(&quot;id&quot;, &quot;p.id&quot;);\r\n                getOrderKeyFieldMap().put(&quot;firstname&quot;, &quot;p.firstName&quot;);\r\n                getOrderKeyFieldMap().put(&quot;lastname&quot;, &quot;p.lastName&quot;);\r\n                getOrderKeyFieldMap().put(&quot;name&quot;, &quot;p.lastName,p.firstName&quot;);\t\t\r\n                getOrderKeyFieldMap().put(&quot;score&quot;, &quot;p.score&quot;);\r\n        }\r\n        \r\n}\r\n<\/pre>\n<p>This takes care of handling the SQL injection problem, lets us isolate the handling of field ordering in one place and it makes it easier to deal with ordering by multiple fields. Note that if you want to define your components in <code>components.xml<\/code> then you can specify this map in the definition. Our query logic will insert the <code class=\"code\">ASC<\/code> and <code class=\"code\">DESC<\/code> where needed depending on the value of the <code class=\"code\">ascending<\/code> flag.<\/p>\n<h2>Ordering the results<\/h2>\n<p>To let the user change the ordering at run time, we need to provide a link which sets the <code class=\"code\">orderKey<\/code>. We can easily do this by changing the header to contain a link to set the <code class=\"code\">orderKey<\/code>. Here we change it for the last name column. <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;h:column&gt;\r\n        &lt;f:facet name=&quot;header&quot;&gt;\r\n                &lt;a:commandLink value=&quot;Last Name&quot;\r\n                        action=&quot;#{personQuery.setOrderKey('lastname')}&quot;\r\n                        reRender=&quot;renderPanel&quot; \/&gt;\r\n        &lt;\/f:facet&gt;\r\n        &lt;h:outputText value=&quot;#{v_person.lastName}&quot; \/&gt;\r\n&lt;\/h:column&gt;\r\n<\/pre>\n<p>If you run this, and click the link, you will notice that the results will order by the field. Click the link again and&#8230;nothing happens.<\/p>\n<p>This is because we haven&#8217;t introduced state into the equation. Each time we click the link, we are posting back to a new instance of the <code class=\"code\">PersonQueryBean<\/code>, not the same one. We could start a conversation which will make our query bean stateful and it will remember the current order key. Alternatively, the simplest way is to put two hidden fields on the page to contain the <code class=\"code\">orderKey<\/code> and the <code class=\"code\">ascending<\/code> values. As we&#8217;ll see later, we will move these out of our page so we don&#8217;t have to add them for each table. For now though, just add two hidden inputs.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;h:inputHidden value=&quot;#{personQuery.orderKey}&quot; \/&gt;\r\n&lt;h:inputHidden value=&quot;#{personQuery.ascending}&quot; \/&gt;\r\n<\/pre>\n<p>Now, we could have left the ordering information in one attribute and used values like <code class=\"code\">\"lastname ASC, firstname ASC\" and \"lastname DESC, firstname DESC\"<\/code> to test and set the ordering without needing two fields and combined it with a list of acceptable fields to prevent SQL injection. However, I prefer to abstract the clause since it decouples it from the view, typos are less of an issue, and if a field name or your model structure changes (i.e. person names are spun off into a separate object), we can change it in one place in the query bean.<\/p>\n<p>Now let us add an icon to the column header so we can see which column we are ordering by and which direction we are ordering the column by. We can do this by evaluating the <code class=\"code\">orderKey<\/code> and <code class=\"code\">ascending<\/code> values.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;h:column&gt;\r\n        &lt;f:facet name=&quot;header&quot;&gt;\r\n                &lt;s:span&gt;\r\n                        &lt;h:commandLink action=&quot;#{personQuery.setOrderKey('score')}&quot;\r\n                                value=&quot;Score&quot; reRender=&quot;#{p_reRender}&quot; \/&gt;\r\n\r\n                        &lt;s:fragment rendered=&quot;#{personQuery.orderKey == 'score'}&quot;&gt;\r\n                                &lt;h:graphicImage value=&quot;\/img\/sort_asc.gif&quot;\r\n                                        rendered=&quot;#{personQuery.ascending}&quot; \/&gt;\r\n                                &lt;h:graphicImage value=&quot;\/img\/sort_desc.gif&quot;\r\n                                        rendered=&quot;#{!personQuery.ascending}&quot; \/&gt;\r\n                        &lt;\/s:fragment&gt;\r\n\r\n                        &lt;s:fragment rendered=&quot;#{ not (personQuery.orderKey == 'score')}&quot;&gt;\r\n                                &lt;rich:spacer width=&quot;19&quot; height=&quot;9&quot; \/&gt;\r\n                        &lt;\/s:fragment&gt;\r\n                &lt;\/s:span&gt;\r\n        &lt;\/f:facet&gt;\r\n        &lt;h:outputText value=&quot;#{v_person.score}&quot; \/&gt;\r\n&lt;\/h:column&gt;\r\n<\/pre>\n<p>Our example is getting a little unwieldy now with 15 lines of html to add sorting to a column. What we&#8217;ll do is wrap this column definition in a reusable facelet. Let&#8217;s call it <code class=\"code\">sortableColumn.xhtml<\/code>. Note that the caption, the query bean, the order key and AJAX render target have all been parameterized.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;ui:composition xmlns=&quot;http:\/\/www.w3.org\/1999\/xhtml&quot;\r\n        xmlns:ui=&quot;http:\/\/java.sun.com\/jsf\/facelets&quot;\r\n        xmlns:h=&quot;http:\/\/java.sun.com\/jsf\/html&quot;\r\n        xmlns:f=&quot;http:\/\/java.sun.com\/jsf\/core&quot;\r\n        xmlns:s=&quot;http:\/\/jboss.com\/products\/seam\/taglib&quot;\r\n        xmlns:rich=&quot;http:\/\/richfaces.org\/rich&quot;\r\n        xmlns:a=&quot;http:\/\/richfaces.org\/a4j&quot;&gt;\r\n        &lt;f:facet name=&quot;header&quot;&gt;\r\n\r\n                &lt;s:span&gt;\r\n                        &lt;a:commandLink action=&quot;#{p_queryBean.setOrderKey(p_field)}&quot;\r\n                                value=&quot;#{p_caption}&quot; reRender=&quot;#{p_reRender}&quot; \/&gt;\r\n\r\n                        &lt;s:fragment rendered=&quot;#{p_queryBean.orderKey == p_field}&quot;&gt;\r\n                                &lt;h:graphicImage value=&quot;\/img\/sort_asc.gif&quot;\r\n                                        rendered=&quot;#{p_queryBean.ascending}&quot; \/&gt;\r\n                                &lt;h:graphicImage value=&quot;\/img\/sort_desc.gif&quot;\r\n                                        rendered=&quot;#{!p_queryBean.ascending}&quot; \/&gt;\r\n                        &lt;\/s:fragment&gt;\r\n\r\n                        &lt;s:fragment rendered=&quot;#{ not (p_queryBean.orderKey == p_field)}&quot;&gt;\r\n                                &lt;rich:spacer width=&quot;19&quot; height=&quot;9&quot; \/&gt;\r\n                        &lt;\/s:fragment&gt;\r\n                &lt;\/s:span&gt;\r\n        &lt;\/f:facet&gt;\r\n\r\n&lt;\/ui:composition&gt;\r\n<\/pre>\n<p>We can use this facelet to define every column that we want to apply ordering to. Here is the html for the Id column.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n        &lt;h:column&gt;\r\n                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;ID&quot; \/&gt;\r\n                        &lt;ui:param name=&quot;p_field&quot; value=&quot;id&quot; \/&gt;\r\n                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                &lt;\/ui:include&gt;\r\n                &lt;h:outputText value=&quot;#{v_person.id}&quot; \/&gt;\r\n        &lt;\/h:column&gt;\r\n\r\n<\/pre>\n<p>If we apply this for each column, we end up with the following person tables. I also added a name column which is last and first name combined. Sorting by last name and then by name, we can see that the ordering is different. This is because the name column orders by last and then first name whereas the last name column orders by the last name<br \/>\nonly (consider the order of Brian,Frank, Jerry and Harrison Ford)<\/p>\n<p><img src=\"\/blog\/img\/personlist3_namesort.png\" \/><\/p>\n<h2>Paginating the Results<\/h2>\n<p>We will use the same type of technique to handle pagination. We will create a pagination facelet which will call the methods on the query bean that it is passed and then trigger an update to the page. Our pagination is fairly simple and the facelet code is included below.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;ui:composition xmlns=&quot;http:\/\/www.w3.org\/1999\/xhtml&quot;\r\n        xmlns:ui=&quot;http:\/\/java.sun.com\/jsf\/facelets&quot;\r\n        xmlns:h=&quot;http:\/\/java.sun.com\/jsf\/html&quot;\r\n        xmlns:f=&quot;http:\/\/java.sun.com\/jsf\/core&quot;\r\n        xmlns:s=&quot;http:\/\/jboss.com\/products\/seam\/taglib&quot;\r\n        xmlns:rich=&quot;http:\/\/richfaces.org\/rich&quot;\r\n        xmlns:a=&quot;http:\/\/richfaces.org\/a4j&quot;&gt;\r\n\r\n        &lt;h:panelGrid columns=&quot;5&quot; styleClass=&quot;paginator&quot; cellpadding=&quot;0&quot;\r\n                cellspacing=&quot;0&quot;\r\n                columnClasses=&quot;pagSmall,pagSmall,pagBig,pagSmall,pagSmall&quot;\r\n                rendered=&quot;#{p_queryBean.nextExists || p_queryBean.previousExists}&quot;&gt;\r\n\r\n                &lt;a:commandLink action=&quot;#{p_queryBean.first}&quot; value=&quot; First&quot;\r\n                        styleClass=&quot;paginatorLink&quot; reRender=&quot;#{p_reRender}&quot; \/&gt;\r\n\r\n                &lt;a:commandLink action=&quot;#{p_queryBean.previous}&quot;\r\n                        reRender=&quot;#{p_reRender}&quot; value=&quot;Previous&quot; styleClass=&quot;paginatorLink&quot; \/&gt;\r\n\r\n                &lt;h:outputText value=&quot;Page #{p_queryBean.activePage}&quot; \/&gt;\r\n                &lt;a:commandLink action=&quot;#{p_queryBean.next}&quot; value=&quot;Next&quot;\r\n                        disabled=&quot;#{!p_queryBean.nextExists}&quot; reRender=&quot;#{p_reRender}&quot;\r\n                        styleClass=&quot;paginatorLink&quot; \/&gt;\r\n\r\n\r\n                &lt;a:commandLink action=&quot;#{p_queryBean.last}&quot; reRender=&quot;#{p_reRender}&quot;\r\n                        style=&quot;align : right&quot; disabled=&quot;#{!p_queryBean.nextExists}&quot;\r\n                        value=&quot;Last&quot; styleClass=&quot;paginatorLink&quot; \/&gt;\r\n\r\n        &lt;\/h:panelGrid&gt;\r\n\r\n        &lt;h:inputHidden value=&quot;#{p_queryBean.firstResult}&quot; \/&gt;\r\n        &lt;h:inputHidden value=&quot;#{p_queryBean.orderKey}&quot; \/&gt;\r\n        &lt;h:inputHidden value=&quot;#{p_queryBean.ascending}&quot; \/&gt;\r\n\r\n&lt;\/ui:composition&gt;\r\n<\/pre>\n<p>If you look at the end of our pagination facelet, we have included the hidden fields to handle ordering, and a new one indicating the first result value. Again, this is so we don&#8217;t have to manage the view state on the server, it gets passed back from the client. We don&#8217;t have to set up parameters nor worry about multiple grids on a page. We have taken the two other hidden values and put them into the pagination facelet which will get included per table or query.<\/p>\n<p>Our code is simple, we have links for first,next, previous and last, and only enable them if the query is able to move in those directions. The links call the appropriate methods on the entity query. We also make use of the AJAX reRender attribute so we only update the table and not the whole page.<\/p>\n<p><img src=\"\/blog\/img\/persons_paginated.png\" \/><\/p>\n<p>So finally, we have a page where we can easily introduce sorting and pagination onto a standard JSF data table. Listed below is the complete page listing. As you can see, we haven&#8217;t really added that much JSF to end up with a table which automatically handles sorting and pagination and AJAX updates to the table.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;h:form&gt;\r\n\r\n        &lt;a:outputPanel id=&quot;renderPanel&quot;&gt;\r\n                &lt;h:dataTable value=&quot;#{personQuery.resultList}&quot; var=&quot;v_person&quot;\r\n                        styleClass=&quot;dataTable&quot; rowClasses=&quot;row1,row2&quot;\r\n                        headerClass=&quot;dataTableHeader&quot;&gt;\r\n                        &lt;h:column&gt;\r\n                                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;ID&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_field&quot; value=&quot;id&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                                &lt;\/ui:include&gt;\r\n                                &lt;h:outputText value=&quot;#{v_person.id}&quot; \/&gt;\r\n                        &lt;\/h:column&gt;\r\n\r\n                        &lt;h:column&gt;\r\n                                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;First Name&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_field&quot; value=&quot;firstname&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                                &lt;\/ui:include&gt;\r\n\r\n                                &lt;h:outputText value=&quot;#{v_person.firstName}&quot; \/&gt;\r\n                        &lt;\/h:column&gt;\r\n\r\n                        &lt;h:column&gt;\r\n                                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;Last Name&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_field&quot; value=&quot;lastname&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                                &lt;\/ui:include&gt;\r\n\r\n                                &lt;h:outputText value=&quot;#{v_person.lastName}&quot; \/&gt;\r\n                        &lt;\/h:column&gt;\r\n\r\n                        &lt;h:column&gt;\r\n                                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;Name&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_field&quot; value=&quot;name&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                                &lt;\/ui:include&gt;\r\n                                &lt;h:outputText value=&quot;#{v_person.name}&quot; \/&gt;\r\n                        &lt;\/h:column&gt;\r\n\r\n                        &lt;h:column&gt;\r\n                                &lt;ui:include src=&quot;sortableHeader.xhtml&quot;&gt;\r\n                                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_caption&quot; value=&quot;Score&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_field&quot; value=&quot;score&quot; \/&gt;\r\n                                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                                &lt;\/ui:include&gt;\r\n\r\n                                &lt;h:outputText value=&quot;#{v_person.score}&quot; \/&gt;\r\n                        &lt;\/h:column&gt;\r\n\r\n                &lt;\/h:dataTable&gt;\r\n\r\n                &lt;ui:include src=&quot;paginator.xhtml&quot;&gt;\r\n                        &lt;ui:param name=&quot;p_queryBean&quot; value=&quot;#{personQuery}&quot; \/&gt;\r\n                        &lt;ui:param name=&quot;p_reRender&quot; value=&quot;renderPanel&quot; \/&gt;\r\n                &lt;\/ui:include&gt;\r\n\r\n        &lt;\/a:outputPanel&gt;\r\n\r\n&lt;\/h:form&gt;\r\n<\/pre>\n<p>This about wraps it up. This code resolves all our problems. We have a mechanism by which we can create sortable tables with pagination that return results to the user quickly without writing any additional code to implement this. The only code we need to write is inserting the orderKey \/ Field mapping values. By adding the hidden fields into the paginator, we make our tables stateless and remove the need to start a conversation or set up parameters for the query values for each table. We have decoupled setting the order type with the actual fields used to achieve it, and made it more secure by removing SQL injection risks. If that were all not enough we have AJAX-ified our table for a better user experience.<\/p>\n<p>If you want to use this code in your own applications, the pieces you will need are the <code class=\"code\">ExtendedEntityQuery<\/code> class, and the 2 pieces of xhtml in <code  class=\"code\">sortableHeader.xhtml<\/code> and <code class=\"code\">pagiantor.xhtml<\/code>. Simply extend your entity queries from the <code class=\"code\">ExtendedEntityQuery<\/code> and they can be used by the sortable columns.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Update : fixed some of the missing images) One common code pattern that we find ourselves writing time and again is the ability to display tables which are paginated and sortable. Ideally, this is something we should try and be able to re-use throughout our application. Current Situation Let&#8217;s start by looking at where we [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[64],"tags":[67,32,8],"_links":{"self":[{"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/24"}],"collection":[{"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":50,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"predecessor-version":[{"id":1074,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/posts\/24\/revisions\/1074"}],"wp:attachment":[{"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.andygibson.net\/blog\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}