How to end FreeMarker processing prematurely in normal way? [duplicate] - freemarker

I have a freemarker template that shows a list of items. When the variable containing the list is empty, I would like to output an empty message and stop the rendering.
eg.
<#if someList?has_content == false>
<span>The list is empty</span>
<#stop/>
</#if>
Is there a directive that I can use rather than <#stop>. This directive ends up putting an error message in the output page. If there is no simpler solution, I can always fall back to
<#if><#else></#if>

There's no such directive. (#stop is for terminating due to error, as you have experienced.)
The use case you refer to reminds me of <#list someList!>...<#items as ...>...</#items>...<#else>...</#list> though. Maybe you can use that construct.

Related

Visualforce Syntax Error for IF statement inside a Apex Repeat

I am receiving a syntax error and having a hard time identifying where I am going wrong.
I have researched several different alternatives such as wrapping <apex outputText> as well as using multiple version of {! leading into my variable calls. Unfortunately, I'm just having a hard time grasping which series of errors I am making to cause this syntax error.
The Crux of the code is:
<td>
{! IF(isTenant, ${woli.Repair_Product__r.Bill_Rate_Retail__c}, ${woli.Repair_Product__r.Bill_Rate__c})}
</td>
For variable References. This is located in a where woli is defined as:
<apex:repeat value="{!woliList}" var="woli">
and isTenant is simply hardcoded in my controller to be false for testing purposes:
public Boolean isTenant = False;
I expected my Apex Repeat command to populate different bill rates depending on the value of isTenant, but of course with the Syntax error I cannot tell if I am on the right track. Helpful tips on when multiple {!} are or are not required in Visual Force references would be helpful. I am also curious when, if ever, I should be using single or double quotation marks to define the output of the if condition.
UPDATE:
I thought perhaps I it was as simple as me not binding the condition statement to a variable in the controller class so I modified to this:
<td>
{! IF({!isTenant}, ${woli.Repair_Product__r.Bill_Rate_Retail__c}, ${woli.Repair_Product__r.Bill_Rate__c})}
</td>
Adding appropriate get/set in the controller. But alas this was not the problem the developer console still gives a mystery Syntax Error.
You don't need $ signs. Dollar is used for special fields that "depends who's looking" and other stuff not really related to data in database. You can have $CurrentPage, $User.Name, $Profile.Name, $Label.someText (that one counts as "depends who's looking" because if your preferred language is French it can display translated version.
And second thing - if you're already inside the {! some merge field syntax } you don't need more curly braces.
Try
{! IF(!isTenant,
woli.Repair_Product__r.Bill_Rate_Retail__c,
woli.Repair_Product__r.Bill_Rate__c
)}

Where are Freemarker Functions set?

I have not used Freemarker before and inherited some templates that won't compile. I have narrowed down the line that is causing problems to:
${text('Text and {0}', 'More Text')}
Where does this text() function come from? I understand that its trying to return the second string injected into the first like: "Text and More Text".
Here is the error:
FreeMarker template error:
For "...(...)" callee: Expected a method, but this has evaluated to an extended_hash (wrapper: f.t.SimpleHash):
modernizr-2.6.2.js is the only javascript imported.
Any ideas why this line is causing problems and where this function should be declared??
It can come from a few places:
From the data-model (one of the parameters you pass to Template.process)
From a shared variable, which is added to the Configuration singleton.
From an #include-d template (or from the template you are in), via #function text or #assign text = ... (or #global text = ...)
From an #import-ed template via #global text = ... (highly unlikely...)
But one potentially interesting thing is that the error says that text does exist, but it's a hash (a Map-like thing), not a callable thing. Maybe something that's also called text shadows the good text? What does ${.data_model.text('Text and {0}', 'More Text')} say?
You mention a JavaScript file. FreeMarker has nothing to do with JavaScript (and it runs on the server, inside the JVM).

Use a expression & HTML in Visualforce if statement

I have HTML and an expression I want to be displayed if the field as a value. If it doesn't, don't display it at all.
{! IF( ISBLANK(GoEvent.Event_Time_End__c), '', '<b>End Time:</b> {!GoEvent.Event_Time_End__c}' ) }
I think I have my condition setup properly, but the HTML isn't rendering and the proper value from the expression isn't displaying. Looks like this.
To get your code to work as you intended you need to wrap your output in an apex:outputText and set escape="false". Note that using escape=false has security implications if you are injecting values the user can edit see: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_security_tips_scontrols.htm
Secondly, the reason you are seeing the # is that you are already inside visualforce syntax with the !IF so no need for the second {!} construct.
Finally I prefer to concatenate the string and visualforce syntax rather than mix.
So a working version would be something like:
<apex:outputText value="{! IF( ISBLANK(GoEvent.Event_Time_End__c), '', '<b>End Time:</b>' + GoEvent.Event_Time_End__c ) }" escape="false"/>
however, given your code is effectively saying only show the output if not null I'd think you are better off with something like this:
<apex:outputPanel layout="false" rendered="{!!ISBLANK(GoEvent.Event_Time_End__c)}">
<b>End Time:</b><apex:outputField value="{!GoEvent.Event_Time_End__c}"/>
</apex:outputPanel>
This is output that is only rendered if the Time isn't blank and output field will localise the time based on user locale etc.

How can I output an XML Node in Freemarker

I'm probably abusing Freemarker here, but I'd like to be able to use it to strip a wrapping element from around the outside of an XML document, something like:
<br:wrap xmlns:br="http://demo.tempuri.com/">
<br:borrower>
<br:id>111-11-1111</br:id>
<br:ssn>111-11-1111</br:ssn>
<br:city>Los Angeles</br:city>
<br:first>John</br:first>
<br:last>Smith</br:last>
<br:phone>310-000-0000</br:phone>
<br:state>CA</br:state>
<br:zip>90025</br:zip>
</br:borrower>
</br:wrap>
I want to remove the outer <wrap/> element. It's easy to select the inner document with:
<#ftl ns_prefixes={"D":"http://demo.tempuri.com"}>
<#assign borrower = doc.wrap.borrower>
{ "result" : "${borrower}" }
The problem here is that the 3rd line is going to result in the good old error:
For "${...}" content: Expected a string or something automatically convertible to string (number, date or boolean), but this has evaluated to a sequence+hash
If I knew exactly what the content and structure of this inner document was I could just walk through it and output the scalar values, but changes all the time. I don't even know the namespaces of all the inner elements (this could even be a problem with the top-level inner object).
I know I could handle this scenario easily with XSLT, but I would much rather find an easy solution in Freemarker.
Any ideas?
${borrower.##markup} should do this.

Formatting Dates in Freemarker Where Date Type is Unknown

I have a Freemarker function whose aim is to print any value passed to it and am having difficulty handling dates in particular.
I understand that when Freemarker cannot determine what portion of a date is in use, that it will error when attempting to print the value directly, and so some special-casing is required for dates, but I've been unable to find a reliable workaround of this feature.
My function looks something like this:
<#function format value=''>
<#if value?is_date>
<#-- code to attempt to handle all types of date -->
<#else>
<#-- handle non-date values -->
</#if>
</#function>
So far, I have tried the following:
First attempt: just always print date and time; e.g. value?datetime
Problem: bombs if the value has already 'been told' it's date-only (e.g. format(value?date) - a usage I want to support)
Second attempt: attempt to print raw value using attempt/recover directives to handle problem cases; e.g.
<#attempt>
<#return value>
<#recover>
<#return value?datetime>
</#attempt>
Problem: the attempt/recover directives don't successful catch the exception - instead it's propagated out as before
I've tried many other things but the above approaches were the more sensible, and unfortunately neither were successful. There seems to be a catch-22: if the date-type is unknown I can only print by choosing an arbitrary type to apply to all date values, but if I attempt to apply that type to a known-type date, it will fail where the types don't match.
Is there any way to determine whether the date type of a value is known before trying to print the value? If so, I could use the ?datetime built in only when necessary.
Ideally, I could tell Freemarker to just print the full date where it's unable to determine the exact type, instead of bombing - but I'm not sure this is currently possible.
Update: In FreeMarker 2.3.21 you can use <#if value?is_date_like>${value?datetime_if_unknown}<#else>...
Yeah, there should exist something like ?is_unknown_type_date, but it doesn't... I'm an FM maintainer so I will add that in 2.3.21 (but don't hold your breath until that's released). Meanwhile, you can write a TemplateMethodModelEx that does just that. Implementing it trivial as you will see, how to make them accessible to templates is a bit underdocumented... One way is just doping the TemplateMethodModelEx into the data-model or into the "shared variable" set of the Configuration. Another is putting this into some of your commonly #import-ed or #included template like <#assign isUnknownTypeDate='com.example.IsUnknownTypeDateMethod'?new()>.
BTW, #recover works for me for this (using a nightly 2.3.21, but I don't remember that it was ever broken). But don't use it for this anyway, as it will log the error. #recover is for emergency situations only, not for normal program flow.
As of providing a default format for unknowns-type dates... I feel uneasy about it as then these issues won't be caught during development, and very few will care to use a different FM configuration for production than for development.

Resources