Filter an array by value - freemarker

Say I have an unordered array called users:
"users": [
{"id": "6", "name": "Bob"},
{"id": "2", "name": "Ryan"}
]
Is there any way to get the user with id == 2 inside my MVEL (or Freemarker) template? If none or multiple, then throw error. It seems possible with #foreach, but I would prefer more concise.

FreeMarker has not built-in functionality for this (it has for {"6": "Bob", "2": "Ryan"}), so you have to write a #function for this.
<#function getById(idNamePairs, id)>
<#local found = false>
<#list idNamePairs as idNamePair>
<#if idNamePair.id == id>
<#if found>
<#stop "Id not unique: ${id}">
</#if>
<#local name = idNamePair.name>
<#local found = true>
</#if>
</#list>
<#if !found>
<#stop "No entry with this id: ${id}">
</#if>
<#return name>
</#function>
Then you can use it like this:
${getById(users, "6")}

Related

find a way to get a property from DDMFormField

Hi I have a question in liferay 7.4 ,
I am using assetRenderer Class to build a freemarker template.
https://docs.liferay.com/portal/7.4-latest/javadocs/portal-kernel/com/liferay/dynamic/data/mapping/kernel/DDMFormFieldValue.html
My problem is I cannot get the url from the featuredImage field which is an image field in a structure, I get a whole value which is a string, I would like to have another way.
<#function getFieldData ddmFormFieldValues fieldReference>
<#list ddmFormFieldValues as ddmFormFieldValue>
<#if ddmFormFieldValue.getDDMFormField().getFieldReference()==fieldReference>
<#if (ddmFormFieldValue)??>
<#assign value=ddmFormFieldValue />
<#return value />
<#else>
<#return null />
</#if>
</#if>
</#list>
<#return null />
</#function>
<#assign ddmFormValuesReader = assetRenderer.getDDMFormValuesReader() />
<#assign ddmFormFieldValues =
ddmFormValuesReader.getDDMFormValues().getDDMFormFieldValues()/>
<#assign newsImage = getFieldData(ddmFormFieldValues, 'featuredImage') />
${newsImage.getValue().getString(locale)}
The result will be a string like this :
{"extension":"jpg","fileEntryId":"631318","groupId":"630625","title":"Dino-bakgrund.png","type":"document","url":"\/documents\/630625\/0\/Dino-bakgrund.png.jpg\/ecffe3b3-333e-3da3-6bb4-732da3d60947?t=1557132929823&imagePreview=1","uuid":"ecffe3b3-333e-3da3-6bb4-732da3d60947"}
Is there a way to get the property directly, since I get a string here ?
I can convert the String to Json and get the result, but this is not a good way something like this :
<#assign newsImage_map = jsonFactoryUtil.createJSONObject(newsImage) />
<#if (newsImage_map.url)?? >
<#assign newsImageUrl = newsImage_map.url />
${newsImageUrl }
</#if>
Is there away that I do not covert to JSON ?

How can i delete parts of my list, if it's two times the same output?

Hy, I'd like to know how i can prevent, that the ouptut will show two times the same date or the same contract type. Furthermore I don't know how i can put a comma behind the last Date/contract type...
At the moment the output would be:
Alessia: 200m2, EUR 100'000, Contract type: Limited/ Limited Start of contract: 2000-01-01 / 2000-01-01 End of contract: 2020-12-31 / 2020-12-31
Jan: 870m2, EUR 3'400'000, Contract type: Limited / Unknown Start of contract: 2001-01-09 / 2002-03-10 End of contrats: 2025-12-31
How I'd like to have the output:
Alessia: 200m2, EUR 100'000, Contract type: Limited, Start of contract: 2000-01-01, End of contract: 2020-12-31
Jan: 870m2, EUR 3'400'000, Contract Types: Limited / Unknown, Start of contracts: 2001-01-09 / 2002-03-10, End of contrats: 2025-12-31
So if there is two times the same date or same contract i only want it once in my list. If it's different it should show all of them and in both cases a comma behind the last output of the list. If you knew how to change the title depending on if there is 0, 1 or two dates following that would be amazing.
<#assign translations = {
"de": {
"bbo": "Per {0}",
"sqm":"m²",
"contract00":"Vertragstyp:",
"contract01":"Befristet",
"contract02":"Unbefristet",
"contract03":"Befristet mit echter Option",
"contract04":"Befristet mit unechter Option",
"contract05":"Amortisation Mieterausbau",
"contract06":"Umsatzmiete",
"contract07":"Andere",
"contract08":"Unbekannt",
"start00":"Vertragsstart:",
"end00":"Vertragsende"
},
"en":{
"bbo": "Per {0}",
"sqm":"m²",
"contract00":"Contract type:",
"contract01":"Limited",
"contract02":"Unlimited",
"contract03":"Limited with real option",
"contract04":"Limited with unreal option",
"contract05":"Amortisation Mieterausbau",
"contract06":"Umsatzmiete",
"contract07":"Other",
"contract08":"Unknown",
"start00":"Start of contract:",
"end00":"End of contract:"
}
}>
<br>
<#assign msg = translations[.lang]>
<#assign currency = valuation.valuationSettings.valuationCurrency>
<#assign rentalUnits = valuation.draftRul.rentalUnits>
<#assign rentalUnitsWithTenant = []>
<#list rentalUnits as ru>
<#if ru.currentLease?? && ru.currentLease.tenant?? >
<#assign rentalUnitsWithTenant = rentalUnitsWithTenant + [ru]>
</#if>
</#list>
<#assign rentalUnitsByTenant = groupBy(rentalUnitsWithTenant, "currentLease.tenant")>
<ul>
<#list rentalUnitsByTenant?keys?sort as tenant>
<#assign rentalUnitsOfTenant = rentalUnitsByTenant[tenant]>
<#assign area=sum(rentalUnitsOfTenant, "areaPerUnitValue")>
<#assign income = sum(rentalUnitsOfTenant, "currentLease.income.income")>
<#assign units = sum(rentalUnitsOfTenant, "units")>
<#if income gte 100000>
<li>
${tenant}: ${area} ${msg["sqm"]}, ${currency} ${income?string[",##0"]},
${msg["contract00"]}
<#list rentalUnitsOfTenant as ru>
<#if ru.currentLease??>
<#if ru.currentLease.contractType= "LIMITED">
<#assign contract = msg["contract01"]>
<#elseif ru.currentLease.contractType="UNLIMITED">
<#assign contract = msg["contract02"]>
<#elseif ru.currentLease.contractType="LIMITED_WITH_REAL_OPTION">
<#assign contract = msg["contract03"]>
<#elseif ru.currentLease.contractType="LIMITED_WITH_UNREAL_OPTION">
<#assign contract = msg["contract04"]>
<#elseif ru.currentLease.contractType="AMORTISATION">
<#assign contract = msg["contract05"]>
<#elseif ru.currentLease.contractType="UMSATZMIETE">
<#assign contract = msg["contract06"]>
<#elseif ru.currentLease.contractType="OTHER">
<#assign contract = msg["contract07"]>
<#elseif ru.currentLease.contractType="UNKNOWN">
<#assign contract = msg["contract08"]>
</#if>
${contract}<#sep>/</#sep>
</#if>
</#list>
${msg["start00"]}
<#list rentalUnitsOfTenant as ru>
<#if ru.currentLease??>
${ru.currentLease.start!}<#sep>/</#sep>
</#if>
</#list>
Enddaten:
<#list rentalUnitsOfTenant as ru>
<#if ru.currentLease.end??>
${ru.currentLease.end!}<#sep>/</#sep>
</#if>
</#list>
</li>
</#if>
</#list>
</ul>
If you have the solution for one of my questions I'm already grateful.
Try to build unique list before printing values, it can be something like in example below. The key thing is seq_contains method.
<#assign uniqueList = []>
<#list rentalUnitsOfTenant as ru>
<#if ru.currentLease??>
<#if ru.currentLease.contractType= "LIMITED">
<#assign contract = msg["contract01"]>
...
</#if>
<#if !uniqueList?seq_contains(contract) >
<#assign uniqueList = uniqueList + [contract]>
</#if>
</#if>
</#list>
<#list uniqueList as contract>
${contract}<#sep>/</#sep>
</#list>

How to convert Spring Boot configuration meta-data files to HTML

I'm sure there must be an elegant way to turn Spring Boot configuration meta-data files into HTML (or markdown or ...). While I could write a parser myself I'm convinced that this has already been solved. Yet, I failed to find a lead for that so far.
Here is a simple example of converting Spring Boot configuration metadata into HTML using org.springframework.boot:spring-boot-configuration-processor and org.freemarker:freemarker libraries.
Parse Metadata
Use classes from spring-boot-configuration-processor library to parse the JSON file,
File metadataFile = new File("spring-configuration-metadata.json");
ConfigurationMetadata metadata =
new JsonMarshaller().read(new FileInputStream(metadataFile));
HTML Generation
Once you have the metadata converted into Java object, use FreeMarker templated to convert it into an HTML file. It uses metadata.ftl template to convert the metadata object into metadata.html.
Configuration cfg = new Configuration(new Version(2, 3, 27));
// template is loaded from 'templates' folder under resources
cfg.setClassForTemplateLoading(
SpringConfigurationMetadataProcessorTest.class, "/templates");
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.US);
cfg.setTemplateExceptionHandler(
TemplateExceptionHandler.RETHROW_HANDLER);
Map<String, Object> input = new HashMap<String, Object>();
input.put("title", "Spring Configuration Metadata Example");
input.put("metadata", metadata);
input.put("GROUP", ItemMetadata.ItemType.GROUP);
input.put("PROPERTY", ItemMetadata.ItemType.PROPERTY);
Template template = cfg.getTemplate("metadata.ftl");
// write output into a file
Writer fileWriter = new FileWriter(new File("metadata.html"));
try {
template.process(input, fileWriter);
} finally {
fileWriter.close();
}
Here is the example metadata.ftl,
<html>
<head>
<title>${title}</title>
</head>
<body>
<h1>${title}</h1>
<#if metadata.hints??>
<section>
<h1>Hints</h1>
<#list metadata.hints as hint>
<section>
<dl>
<dt><b>name: </b>${hint.name}</dt>
<#if hint.values?? && hint.values?size != 0>
<dt><b>values:</b></dt>
<#list hint.values as value>
<#if value.value??>
<dd><b>value: </b>${value.value}</dd>
</#if>
<#if value.description??>
<dd><b>description: </b>${value.description}</dd>
</#if>
<br/>
</#list>
</#if>
<#if hint.providers?? && hint.providers?size != 0>
<dt><b>providers:</b></dt>
<#list hint.providers as provider>
<#if provider.name??>
<dd><b>name: </b>${provider.name}</dd>
</#if>
<#if provider.parameters?? && provider.parameters?size != 0>
<dd><b>parameters:</b></dd>
<#list provider.parameters as key, value>
<dd> <b>${key}: </b>${value}
</dd>
</#list>
</#if>
<br/>
</#list>
</dl>
</#if>
</section>
</#list>
</section>
</#if>
<#if metadata.items??>
<section>
<h1>Groups</h1>
<#list metadata.items as item>
<#if item.isOfItemType(GROUP)>
<section>
<dl>
<#if item.sourceType??>
<dt><b>sourceType: </b> ${item.sourceType}</dt>
</#if>
<#if item.name??>
<dt><b>name: </b> ${item.name}</dt>
</#if>
<#if item.description??>
<dt><b>description: </b> ${item.description}</dt>
</#if>
<#if item.type??>
<dt><b>type: </b> ${item.type}</dt>
</#if>
<#if item.sourceMethod??>
<dt><b>sourceMethod: </b> ${item.sourceMethod}</dt>
</#if>
<#if item.defaultValue??>
<#if item.defaultValue?is_enumerable>
<dt><b>defaultValue: </b></dt>
<#list item.defaultValue as df>
<dd>${df}</dd>
</#list>
<#else>
<dt><b>defaultValue: </b> ${item.defaultValue}</dt>
</#if>
</#if>
<#if item.deprecation??>
<dt><b>deprecation: </b></dt>
<#if item.deprecation.reason??>
<dd><b>reason: </b> ${item.deprecation.reason}</dd>
</#if>
<#if item.deprecation.replacement??>
<dd><b>replacement: </b> ${item.deprecation.replacement}</dd>
</#if>
<#if item.deprecation.level??>
<dd><b>level: </b> ${item.deprecation.level}</dd>
</#if>
</#if>
</dl>
</section>
</#if>
</#list>
<h1>Properties</h1>
<#list metadata.items as item>
<#if item.isOfItemType(PROPERTY)>
<section>
<dl>
<#if item.sourceType??>
<dt><b>sourceType: </b> ${item.sourceType}</dt>
</#if>
<#if item.name??>
<dt><b>name: </b> ${item.name}</dt>
</#if>
<#if item.description??>
<dt><b>description: </b> ${item.description}</dt>
</#if>
<#if item.type??>
<dt><b>type: </b> ${item.type}</dt>
</#if>
<#if item.sourceMethod??>
<dt><b>sourceMethod: </b> ${item.sourceMethod}</dt>
</#if>
<#if item.defaultValue??>
<#if item.defaultValue?is_enumerable>
<dt><b>defaultValue: </b></dt>
<#list item.defaultValue as df>
<dd>${df}</dd>
</#list>
<#else>
<dt><b>defaultValue: </b> ${item.defaultValue}</dt>
</#if>
</#if>
<#if item.deprecation??>
<dt><b>deprecation: </b></dt>
<#if item.deprecation.reason??>
<dd><b>reason: </b> ${item.deprecation.reason}</dd>
</#if>
<#if item.deprecation.replacement??>
<dd><b>replacement: </b> ${item.deprecation.replacement}</dd>
</#if>
<#if item.deprecation.level??>
<dd><b>level: </b> ${item.deprecation.level}</dd>
</#if>
</#if>
</dl>
</section>
</#if>
</#list>
</section>
</#if>
</body>
</html>

How to group a list of objects by date in Freemarker?

<#setting date_format="dd/MM/yyyy">
<#assign data1 = "14/05/2016" />
<#assign data2 = "20/05/2016" />
<#assign data3 = "19/06/2016" />
<#assign events_list = [
{"name":"Event Lorem", "date":data1?date},
{"name":"Event Lipsum", "date":data2?date},
{"name":"Event Free", "date":data2?date},
{"name":"Event Dolor", "date":data3?date},
{"name":"Event Sit", "date":data1?date}
] />
I have this list of events and I sorted them by date:
<h5>Order by date:</h5>
<#list events_list?sort_by("date") as event>
<p>${event.name}: ${event.date}</p>
</#list>
Now I want to group them by date because each one can have hours.
Like in this example:
How can I accomplish this in Freemarker?
<#setting date_format="dd/MM/yyyy">
<#assign dataNull = "01/01/1900" />
<#assign data1 = "14/05/2016" />
<#assign data2 = "20/05/2016" />
<#assign data3 = "19/06/2016" />
<#assign events_list = [
{"name":"Event Lorem", "date":data1?date},
{"name":"Event Lipsum", "date":data2?date},
{"name":"Event Free", "date":data2?date},
{"name":"Event Dolor", "date":data3?date},
{"name":"Event Sit", "date":data1?date}
] />
<h5>Order by date:</h5>
<#assign lastDate = dataNull?date>
<#list events_list?sort_by("date") as event>
<#if lastDate != event.date >
<p><b> ${event.date}</b></p>
</#if>
<#assign lastDate = event.date >
<p>${event.name}: ${event.date}</p>
</#list>
Order by date:
14/05/2016
Event Lorem: 14/05/2016 14/05/2016
Event Sit: 14/05/2016 14/05/2016
20/05/2016
Event Lipsum: 20/05/2016 20/05/2016
Event Free: 20/05/2016 20/05/2016
19/06/2016
Event Dolor: 19/06/2016 19/06/2016
See also this answer about how to implement grouped listing with a macro. I think this is more reusable then the other answer: https://stackoverflow.com/a/61588885/606679

How to get simple freemarker if statement match some string

I have the following freemarker code
<#assign carsPriceDescriptionSB = "Price guide" >
<#if vehicle.getPriceDescription == carsPriceDescriptionSB >
<div class="cgl304 data-source small">Some text
<br/><br/>
</div>
</#if>
What I want to do is check that the value of vehicle.getPriceDescription() is equal to Price guide and if the result is true display the block of code
To access the get method you should drop the 'get' or explicitly specify the method name followed by brackets. Avoid using the second method unless necessary.
Normally omit the get prefix
<#assign carsPriceDescriptionSB = "Price guide" >
<#if vehicle.priceDescription == carsPriceDescriptionSB >
<div class="cgl304 data-source small">Some text
<br/><br/>
</div>
</#if>
Or if it is not a get method then specify the entire method name
<#assign carsPriceDescriptionSB = "Price guide" >
<#if vehicle.readPriceDescription() == carsPriceDescriptionSB >
<div class="cgl304 data-source small">Some text
<br/><br/>
</div>
</#if>

Resources