How to allow end user sorting a list

  Written by The Jahia Team
 
Developers
   Estimated reading time:

If you want to allow an end user to sort a list, then you should build a query on your list. 
In this basic example, we will show how to allow the end user to sort a list using the title of each list item, or the publication date of each item. We will also allow the end user to choose the sort order.

Answer

First, imagine this very simple definition:

[jnt:myDocumentList] > jnt:contentList, jmix:droppableContent, mix:title
 + * (jnt:myDocument)
[jnt:myDocument] > jnt:content, mix:title

It declares a jnt:myDocumentList list of jnt:myDocument items. Each item have a mix:title, meaning that it will declare a jcr:title property

First, we will prepare both list and content views.
Here is the list view for jnt:myDocumentList. We simply iterate on all items of the list and relaying the content view of all children. We also allow the editor to add jnt:myDocument items in the list

jnt_myDocumentList/html/myDocumentList.jsp

<%@ page language="java" contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="template" uri="http://www.jahia.org/tags/templateLib" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<template:include view="hidden.header"/>

<h1>${currentNode.displayableName}</h1>

<c:forEach items="${moduleMap.currentList}" var="subchild" begin="${moduleMap.begin}" end="${moduleMap.end}">
    <template:module node="${subchild}" editable="${moduleMap.editable && !resourceReadOnly}"/>
</c:forEach>
<c:if test="${renderContext.editMode}">
    <template:module path="*" nodeTypes="jnt:myDocument"/>
</c:if>

As you can see, on the top of this file we use the <template:include view="hidden.header"/>. This hidden.header calls a "loader" whose role is to get all nodes to display and store them in ${moduleMap}

And here is the very minimalist view of the content: jnt_myDocument/html/myDocument.jsp

<%@ page language="java" contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%--@elvariable id="currentNode" type="org.jahia.services.content.JCRNodeWrapper"--%>

<h2>${currentNode.properties['jcr:title'].string}</h2>
<p><fmt:formatDate type="both" dateStyle="medium" timeStyle="medium"
                   value="${currentNode.properties['j:lastPublished'].time}"/></p>

At this time of the development, there is no way for the end user to sort the list. The idea here is to generate URLs with parameters to send the nodeType (it will be the j:lastPublished or the jcr:title) we want to sort on, and also the sort order (it will be asc or desc).

To do it, we create 4 dedicated links in the list view:

<c:url var="publishedAscUrl" value="${renderContext.mainResource.node.url}">
    <c:param name="nodeType" value="j:lastPublished"/>
    <c:param name="sortOrder" value="asc"/>
</c:url>
<c:url var="publishedDescUrl" value="${renderContext.mainResource.node.url}">
    <c:param name="nodeType" value="j:lastPublished"/>
    <c:param name="sortOrder" value="desc"/>
</c:url>
<c:url var="titleAscUrl" value="${renderContext.mainResource.node.url}">
    <c:param name="nodeType" value="jcr:title"/>
    <c:param name="sortOrder" value="asc"/>
</c:url>
<c:url var="titleDescUrl" value="${renderContext.mainResource.node.url}">
    <c:param name="nodeType" value="jcr:title"/>
    <c:param name="sortOrder" value="desc"/>
</c:url>

Sort by published date <a href="${publishedAscUrl}">asc</a> | <a href="${publishedDescUrl}">desc</a><br/>
Sort by title <a href="${titleAscUrl}">asc</a> | <a href="${titleDescUrl}">desc</a><br/>

And as the output of the list will be different depending on the value of each parameter, we will need to deal with the cache. To do it we will create a property file for the list 
jnt_myDocumentList/html/myDocumentList.properties

cache.requestParameters=sortOrder,nodeType

And now we can create our query in a jnt_myDocumentList/html/myDocumentList.hidden.load.jsp
First, we get the parameters, and if we have values for both nodeType and sortOrder then we create a query definition and we set it to our moduleMap
We limit the query to the nodes of the list and to the type jnt:myDocument

<%@ page language="java" contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="query" uri="http://www.jahia.org/tags/queryLib" %>
<%--@elvariable id="currentNode" type="org.jahia.services.content.JCRNodeWrapper"--%>
<c:set var="nodeType" value="${param.nodeType}"/>
<c:set var="sortOrder" value="${param.sortOrder}"/>

<c:if test="${! empty nodeType && ! empty sortOrder}">
    Let's build the query sorted by ${nodeType} - ${sortOrder}

    <query:definition var="listQuery">
        <query:selector nodeTypeName="jnt:myDocument"/>
        <query:descendantNode path="${currentNode.path}"/>
        <query:sortBy propertyName="${nodeType}" order="${sortOrder}"/>
    </query:definition>
    <c:set target="${moduleMap}" property="listQuery" value="${listQuery}"/>
</c:if>

And that's all. Now we have a user sortable list. Here would be the result:

sortList.png