I've got a structure for my template for creating web content.
Parent element of text named List and it has got repeatable child element named Item.
When I try to add two or more elements, I can't show them all with my template. It shows only first element of Item.
Here is my template
<#if Information.getSiblings()?has_content>
<#list Information.getSiblings() as information>
<h1>${information.getChild('Title').getData()}</h1>
<p>${information.getChild('Description').getData()}</p>
<ul>
<#list information.getChild('List').getSiblings() as item>
<li>${item.getChild('Item').getData()}</li>
</#list>
</ul>
</#list>
UPD
Deal with it. This is will display all items in list
<#if Information.getSiblings()?has_content>
<#list Information.getSiblings() as information>
<h1>${information.getChild('Title').getData()}</h1>
<p>${information.getChild('Description').getData()}</p>
<ul>
<#list information.getChild('List').getChild('Item').getSiblings() as item>
<li>${item.getData()}</li>
</#list>
</ul>
</#list>
I think you should navigate the Information structure using getChildren() instead of getSiblings()
Something like
<#if parent.getChildren()?has_content>
<#list parent.getChildren() as information>
...
</#list>
</#if>
Using getSiblings() you are missig one of the "brothers"
Related
I have this Document Type Structure:
I can get the value of the fields that do not have a children (in this example the field with the name Field):
<#if imageMimeTypes?seq_contains(entry.getMimeType()) >
<#assign fileEntryType = DLFileEntryTypeService.getFileEntryType(fileEntryTypeId) />
<#assign dlFileVersion = DLFileVersionService.getLatestFileVersion(fileEntry.getUserId(), fileEntry.getFileEntryId()) />
<#assign fieldsMap = fileEntry.getFieldsMap(dlFileVersion.getFileVersionId()) />
<#list fieldsMap?keys as structureKey>
<#list fieldsMap[structureKey].iterator() as field>
<#if field.getName() == 'Field'>
<#assign Field = field.getValue() />
</#if>
</#list>
</#list>
Value: ${Field}
</#if>
But when I have a repeatable field with children fields I can't get neither the value of the repeatable field nor the value of its children.
<#list fieldsMap?keys as structureKey>
<#list fieldsMap[structureKey].iterator() as field>
<#if field.getName() == 'Repeatable_field'>
<#assign RepeatableField = field.getName() />
</#if>
</#list>
</#list>
Value: ${RepeatableField}
I get this error:
Expecting a string, date or number here, Expression RepeatableField
is instead a freemarker.template.SimpleSequence
UPDATE:
I managed to get the value of Repeatable_field using field.getValues(locale) method.
But I still can't get the value of its children:
<#list fieldsMap?keys as structureKey>
<#list fieldsMap[structureKey].iterator() as field>
<#if field.getName() == 'Repeatable_field'>
<#assign repeatableFieldValues = field.getValues(locale) />
<#list repeatableFieldValues as val>
<#assign Field = val /><#-- parent Value -->
<#-- assign childrenField = val.Children_field.getValue() --><#-- children Value -->
</#list>
</#if>
</#list>
</#list>
In Liferay 7.3, I get the repeatable field values within the ADT in this way:
<#if entries?has_content>
<#list entries as entry>
<#if entry.getClassName() == "com.liferay.journal.model.JournalArticle" >
<#assign assetRenderer = entry.getAssetRenderer() />
<#assign article = assetRenderer.getArticle() />
<#assign articleStructure = article.getDDMStructure() />
<#assign articleStructureFields = articleStructure.getRootFieldNames() />
<#assign document = saxReaderUtil.read(article.getContent()) />
<#assign rootElement = document.getRootElement() />
<#list articleStructureFields as field>
<#attempt>
<#assign xPathSelectorDocument = saxReaderUtil.createXPath("dynamic-element[#name='${field}']") />
<#assign fieldContent = xPathSelectorDocument.selectSingleNode(rootElement).getStringValue() />
<#assign fieldNodes = xPathSelectorDocument.selectNodes(rootElement) />
<#if field == 'User'> <#-- Field - Simple -->
<#assign user = fieldContent />
<#elseif field == 'Actions'> <#-- Field - Repeatable -->
<#assign listActions = [] />
<#list fieldNodes as node>
<#assign listActions = listActions + [node.getStringValue()] />
</#list>
</#if>
<#recover>Error</#attempt>
</#list>
<#-- Field - Simple -->
${user}
<#-- Field - Repeatable -->
<#list listActions as action>
${action}
</#list>
</#if>
</#list>
</#if>
Within my Liferay 6.2 EE Webcontent template i have the following freemarker code:
<#list teaserHeader.getSiblings() as teaser_header>
<#if getterUtil.getBoolean(teaser_header.teaserVisible.getData())>
<h2 class="section-headline">${teaserHeader.getData()?html}</h2>
<div class="inner-15">
<div class="general-wrapper inner-15-content bound" >
<#if teaser_header.teaserImage.getData() != "">
<div class="product-image-wrapper left">
<img src="${teaser_header.teaserImage.getData()}" width="" height=""/>
</div>
</#if>
<div class="product-teaser-info left">${teaser_header.teaserContent.getData()}</div>
<div class="clearfix"></div>
</div>
</div>
</#if>
</#list>
Unfortunately we have to switch to Velocity.
What's the best approach to transform freemarkers list tag to Velocity ?
I already adopted everything else (if tags, method calls, ...)
But i have some troubles with the list tag.
I tried to do it with foreach in Velocity but i failed...
Thanks
In velocity it should look something like this:
#if (!$teaserHeader.getSiblings().isEmpty())
#foreach ($teaser_header in $teaserHeader.getSiblings())
...
#end
#end
I have created and ADT (Application Display Template) for Asset Publisher which displays web-contents. If a link is clicked the web-content should open in maximized mode.
<#if entries?has_content>
<#list entries as entry>
<#assign renderer = entry.getAssetRenderer() />
<#assign className = renderer.getClassName() />
<#if className == "com.liferay.portlet.journal.model.JournalArticle">
<#assign journalArticle = renderer.getArticle() />
<#assign document = saxReaderUtil.read(journalArticle.getContentByLocale(locale.toString())) />
<#assign assetURL = assetPublisherHelper.getAssetViewURL(renderRequest, renderResponse,entry) />
<div class="molisana-product">
<a href="${assetURL}">
<h3 class="product-title">
${entry.getTitle(locale)}
</h3>
</a>
</div>
</#if>
</#list>
</#if>
The important bit is :
<#assign assetURL = assetPublisherHelper.getAssetViewURL(renderRequest, renderResponse,entry) />
I tried with setWindowState <a href="${assetURL.setWindowState(WindowState.MAXIMIZED)}"> but doesn't work.
I have content with a structure and a template and I want to access the tags of the content to show it in the template.
In a previous Application Display Template of an Asset Publisher, i got the tags with the ServiceLocator like this:
<#list entries as entry>
<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetEntryLocalService") />
<#assign assetTagLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetTagLocalService") />
<#assign assetTags = assetTagLocalService.getEntryTags(entry.getEntryId()) />
<#list assetTags as tag>
<#if tag.getName() != "startseite">
${tag.getName()}
</#if>
</#list>
</#list>
In my Template, I swapped entry with .vars['reserved-article-id'].data but then I get an error:
Method public final java.util.List com.sun.proxy.$Proxy562.getEntryTags(long) throws com.liferay.portal.kernel.exception.SystemException threw an exception when invoked on com.liferay.portlet.asset.service.impl.AssetTagLocalServiceImpl#6bc73e2b
How do you get this to work in a template?
Tags are associated with the assetEntry using it's resourcePrimKey, so you can do this:
<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetEntryLocalService") />
<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.portlet.journal.service.JournalArticleLocalService") />
<#assign article = journalArticleLocalService.getArticle(getterUtil.getLong(scopeGroupId), .vars['reserved-article-id'].data)>
<#assign asset = assetEntryLocalService.getEntry('com.liferay.portlet.journal.model.JournalArticle', article.resourcePrimKey) >
<#list asset.getTags() as tag>
<code>${tag.name}</code>
</#list>
As of Liferay 7, you should be able to use the following:
<#list entries as entry>
<#assign
entry = entry
/>
<#list entry.tagNames as tag>
${tag}
</#list>
</#list>
I tried to create a Web Content with a Template that contains the navigation (list of pages):
<nav id="navigation">
<ul>
<#list nav_items as nav_item>
<#assign nav_item_css_class = "" />
<#if nav_item.isSelected()>
<#assign nav_item_css_class = "selected" />
</#if>
<li class="${nav_item_css_class}">
${nav_item.getName()}
<#if nav_item.hasChildren()>
<ul class="child-menu">
<#list nav_item.getChildren() as nav_child>
<#assign nav_child_css_class = "" />
<#if nav_item.isSelected()>
<#assign nav_child_css_class = "selected" />
</#if>
<li class="${nav_child_css_class}">
${nav_child.getName()}
</li>
</#list>
</ul>
</#if>
</li>
</#list>
</ul>
</nav>
But I get this error:
Expression nav_items is undefined
In my theme navigation.ftl it works but in the WCM ftl (FreeMarker) doesn't work.
Then, how can I get the list of pages in WCM?
The list of pages is available only in ADTs (Application Display Templates), not in WCM templates.
If you really need the list and can use ADTs, use navItems variable instead. The variable nav_items only works in themes (for backward compatibility, I guess).
Documentation - hard to find. Use the force, read the source - on GitHub.
You may want to use a handy Freemarker script to display all available variables - see Dumping ADT+WCM Template Variables on James Falkner's blog.