Iterar campos repetibles en un Application Display Template de Liferay 7

Una de las cosas más complicadas de comprender es cómo usar los llamados repeatable fields en un Application Display Template (ADT) en Liferay 7; debido a que no disponemos de tanta documentación oficial. Por tal motivo quisiera compartir contigo un ejemplo de una ADT para el famoso Asset Publisher; comencemos:

  1. Imagina que tienes una Estructura (Structure) con un campo de tipo “Documents and Library” llamado attachment el cual ha sido configurado como repeatable=true.
  2. Ahora bien, necesitas crear un listado de todos los attachments y obtener tanto el link al documento, como su etiqueta (label).
<#if entries?has_content>
    <!-- START: item loop -->
    <div class="container">
        <div class="row">
            <#list entries as entry>
                <#assign renderer = entry.getAssetRenderer()/>
                <#assign className = renderer.getClassName() />
                <#if className == "com.liferay.journal.model.JournalArticle">
                    <#assign journalArticle = renderer.getArticle() />
                    <#assign document = saxReaderUtil.read(journalArticle.getContent()) />
                    <#assign allAttachments = document.selectNodes( "//dynamic-element[@name='attachment']") />
                    <!-- START: item html -->
                    <div class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
                        <div class="media card-file">
                            <div class="media-body">
                                <#list allAttachments.iterator() as attachment>

                                    <#if attachment.valueOf( "dynamic-element[@name='fileLabel']")??>
                                        <#assign fileLabel = attachment.valueOf( "dynamic-element[@name='fileLabel']") />
                                        <#else>
                                            <#assign fileLabel="Download File" />
                                    </#if>

                                    <#if attachment.valueOf( "dynamic-content")??>
                                        <#assign fileLink = attachment.valueOf( "dynamic-content") />
                                        <#else>
                                            <#assign fileLink="#" />
                                    </#if>

                                    <div class="card-file__attachment">
                                        <a href="${fileLink?trim}" target="_blank">${fileLabel?trim}</a>
                                    </div>
                                </#list>
                            </div>
                        </div>
                    </div>
                    <!-- END: item html -->
                </#if>
            </#list>
        </div>
    </div>
    <!-- END: item loop -->
</#if>

Lo más importante en el código de Freemarker anterior es que estamos utilizando una query de XPath para obtener todos los nodos del XML que representa nuestro Journal Article:

<#assign allAttachments = document.selectNodes( "//dynamic-element[@name='attachment']") />

Acto seguido procedemos a iterar ese NodeList, usando la instrucción #list de Freemarker:

<#list allAttachments.iterator() as attachment>
// Do something here :)
</#list>

Tip. Si tienes dudas qué es una ADT; esta es la definición oficial de la documentación de Liferay:

The application display template (ADT) framework allows Liferay administrators to override the default display templates, removing limitations to the way your site’s content is displayed. With ADTs, you can define custom display templates used to render asset-centric applications. For example, you may want to show blog entries horizontally instead of vertically, or list your assets in the asset publisher application in different sizes.
https://dev.liferay.com/discover/portal/-/knowledge_base/6-2/using-application-display-templates