Highlighted

Simple AEM Granite Order Widget (Draggable List) | AEM Community Blog Seeding

kautuk_sahni

Community Manager

27-09-2020

BlogImage.jpg

Simple AEM Granite Order Widget (Draggable List) by Ahmed Musallam

Abstract

Recently, we had the need for an authoring experience where, an author can re-order a list of fixed tabs to their desired order. The only Granite widget that allows drag-n-drop ordering is the multifield, but we don’t need a multifield, we just wanted the ability to order a fixed list.

An Existing solution
ACS Commons has this Draggable Lists Widget but I did not want to include ACS commons just for that widget. Additionally, I looked at the implementation for that widget and it seemed to be complex granted it might be solving a different problem. It also used Coral UI 2; we are on AEM 6.4 where Coral UI 3 is the latest Coral version.

A Simple Solution
If you look at Coral UI 3 documentation, the only component that allows drag-n-drop ordering is the Coral.Table component. Which means, we can create a Granite widget that uses that UI to render a list!

Here is the widget JSP impl: (Java 8)

for the purpose of this post, I’ve created /apps/widgets/orderedList/orderedList.jsp

Here, I render each item in the list as a hidden field with the same “name”.

The order of the hidden fields in the HTML is what determines the saved order in the JCR content node/prop.

This also means that we dont need ANY custom JS to make this work! just the OOTB CUI3 Table component!

<%--
Renders a List of items for ordering purposes only
--%><%
%><%@ include file="/libs/granite/ui/global.jsp" %><%
%><%@ page session="false"
import="java.util.Iterator,
com.adobe.granite.ui.components.AttrBuilder,
com.adobe.granite.ui.components.Tag,
com.adobe.granite.ui.components.Config,
org.apache.sling.api.resource.ValueMap,
java.util.stream.StreamSupport,
java.util.stream.Collectors,
java.util.*" %>
<%--###
Ordered List
====
// TODO
.. granite:servercomponent:: widgets/orderedList
Renders a List of items for ordering purposes only

It has the following content structure:
+ myList
- sling:resourceType = "widgets/orderedList"
- name = "./myList"
- title = "My List"
+ items
+ item1
- text = "Item 1"
- value = "item1"
+ item 2
- text = "Item 2"
- value = "item2"
###--%>
<%
if (!cmp.getRenderCondition(resource, false).check()) {
return;
}
Tag tag = cmp.consumeTag();
AttrBuilder attrs = tag.getAttrs();
attrs.addClass("coral-Well");
cmp.populateCommonAttrs(attrs);
Config cfg = cmp.getConfig();
String title = cfg.get("title", String.class);
String name = cfg.get("name", String.class);

// the easy way to do this...
String cleanName =
name != null
? name.replace(".", "").replace("/", "")
: "";
String tableId = "order-table-" + cleanName;
String hiddenInputId = "order-input-" + cleanName;
String[] values = cmp.getValue().getContentValue(name, new String[0]);
List valuesList = Arrays.asList(values);
Iterator itemsIterator = cmp.getItemDataSource().iterator();

// server-side ordering of values based on already saved order
List items = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(itemsIterator, Spliterator.ORDERED),
false
).sorted(
Comparator.comparing(item -> {
ValueMap vm = ((Resource) item).getValueMap();
String val = vm.get("value", "");
return valuesList != null ? valuesList.indexOf(val) : 0;
})
).map(Resource::getValueMap)
.collect(Collectors.toList());
%>
> <% for (ValueMap vm : items) { %> <% } %>
<%=title%>  
<%=vm.get("text", "") %> "/>  
 

Read Full Blog

Simple AEM Granite Order Widget (Draggable List)

Q&A

Please use this thread to ask the related questions.

AEM AEMEBlogSeeding Experience Manager