Named scopes in templates - freemarker

Is it possible to name some blocks inside ftl and get them on java side? For example something like with incrorrect syntax maybe
#emailSubject[
This is email subject]
#emailMessage
[Email multi-
line message!!
Hi all]
and java side looks like
template.process("template.ftl", resultModelOrSomethingElse);
String emailSubject = resultModelOrSomethingElse.getEmailSubject();
String emailMessag = resultModelOrSomethingElse.getEmailMessage();

Out-of-the-box, you can do this:
<#assign emailSubject>This is the email subject</#assign>
<#assign emailMessage>
This is the email message...
</#assign>
and then:
// Same as template.process, but you will have the Environment:
Environment env = template.createProcessingEnvironment(dataModel, out);
env.process();
// Extract top-level variables:
TemplateModel emailSubject = env.getVariable("emailSubject");
TemplateModel emailMessage = env.getVariable("emailMessage");
(If it's something that you will do a lot, you might want to streamline this in the template. Like <#emailSubject>This is the email subject</#> is terser and more fool-proof, as it will immediately fail if somebody makes a mistake in the "emailSubject" variable name.)

Related

Freemarker assigning escaped ${expression} to a variable

I need to assign an escaped ${expression} to a variable in Freemarker
From the question here, it's clear that we can escape the $ sign in this way
${r"${expression}"}
This works perfectly outside Freemarker context, but doesnot working inside. I am trying to do
<#assign x = "${r"${expression}"}">
But getting the following error:
Template inclusion failed:
You can't use "${" here as you are already in FreeMarker-expression-mode. Thus, instead of ${myExpression}, just write myExpression. (${...} is only needed where otherwise static text is expected, i.e, outside FreeMarker tags and ${...}-s.)
What is the way to achieve this? Thanks in advance.
I had to spent some time to figure out the following scenarios to escape ${expression} -
In Freemarker assignment:
<#assign var = r"${expression}">
In html attribute:
Some link
In Freemarker concatenation:
<#assign x = "something&"+r"${expression}"/>
Like this:
<#assign x = r"${expression}">

How can I set a FreeMarker variable with an interpolated value? error: "You can't use "${" here as you are already in FreeMarker-expression-mode."?

I am absolutly new in FreeMarker and I have the following problem working on a Spring MVC application that use this template engine.
So into a controller method I put an int representing the current year (2016) into the model, in this way:
model.addAttribute("annoCorrente", annoCorrente);
Then, into my FreeMarker page I have to assign this value to a variable, so I write the following expression:
<#assign a = ${annoCorrente}>
But in this way I obtain the following error message:
[col. 86] You can't use "${" here as you are already in FreeMarker-expression-mode. Thus, instead of ${myExpression}, just write myExpression. (${...} is only needed where otherwise static text is expected, i.e, outside FreeMarker tags and ${...}-s.)
Why? How can I correctly initizialize a FreeMarker variable with the value obtained from the model associated to this view?
Change <#assign a = ${annoCorrente}> to <#assign a = annoCorrente>
(or you can do <#assign a = "${annoCorrente}"> but this is not recommended)

FMPP: How to set a Freemarker variable from a BeanShell script

Is it possible to set one or more freemarker variable in a case like:
<#assign test=pp.loadData('eval', '
a="test1";
b="test2";
return "test";')>
and having access to a and b in the freemarker script ?
I guess it can't be done without writing a custom DataLoader. I'm saying "guess" because maybe I don't know about a BeanShell trick. The closest I could get is using return this.namespace; and then ${test.getVariable('a')}. This is too verbose of course.
Update:
Actually, the following horror is even closer:
<#assign test=pp.loadData('eval', '
a="test1";
b="test2";
// This should be factored out into a common function somehow
ns = this.namespace;
vars = new HashMap();
for (name : ns.getVariableNames()) {
vars.put(name, ns.getVariable(name));
}
return vars;
')>
${test.a}

My FreeMarker method returns a string with ${variable} -- how to force FreeMarker to parse that?

I've created a class that implements TemplateMethodModelEx from FreeMarker. Pretend the exec() function returns a String: "Hello ${username}"
I assign the class to a method in the data model:
dataModel.put("myMethod", myClassInstance);
dataModel.put("username", "John Doe");
My HTML template looks like this:
<p>${myMethod()}</p>
Which means that the following output is generated, when the template is processed:
<p>Hello ${username}</p>
Since there is actually a username value in my data model, I'd rather want the output to be:
<p>Hello John Doe</p>
How do I tell FreeMarker to parse the result of myMethod()? I tried both ?eval and ?interpret and both fail to accomplish what I want. Is this possible with FreeMarker?
You need to remove ${} from a string to use ?eval. Return username as a string from your method and use ?eval or get variable from .vars.
<p>${classInstance.myMethod()?eval}</p>
or
<p>${.vars[classInstance.myMethod()]}</p>
If you want to return not just a variable name but a string with an expression (e.g. "Hello ${username}") from the method then use ?interpret.
<#assign inlineTemplate = classInstance.myMethod()?interpret>
<#inlineTemplate />

Freemarker - replace & with &

If i have the & symbol in some field (from a db, cannot be changed), and i want to display this via freemarker... but have the display (from freemarker) read &, what is the way to do so?
To reiterate, I cannot change the value before hand (or at least, I don't want to), i'd like freemarker to "unmark" &.
To double re-iterate, this is a value that is being placed with a lot of other xml. The value itself is displayed on its own, surrouded by tags... so something like
<someTag>${wheeeMyValueWithAnAmpersand}<someTag>
As a result, i don't want all ampersands escaped, or the xml will look funny... just that one in the interpolation.
Oh goodness.
I see the problem: the code was written like this:
<#escape x as x?xml>
<#import "small.ftl" as my>
<#my.macro1/>
</#escape>
and at which i'd assumed that the excape would excape all the calls within it - it is certainly what the documentation sort of implies
http://freemarker.org/docs/ref_directive_escape.html
<#assign x = "<test>"> m1>
m1: ${x}
</#macro>
<#escape x as x?html>
<#macro m2>m2: ${x}</#macro>
${x}
<#m1/>
</#escape>
${x}
<#m2/>
the output will be:
<test>
m1: <test>
<test>
m2: <test>
However it appears that when you import the file, then this isn't the case, and the escape... escapes!
SOLUTION:
http://watchitlater.com/blog/2011/10/default-html-escape-using-freemarker/
the above link details how to solve the problem. In effect, it comes down to loading a different FreemakerLoader, one that wraps all templates with an escape tag.
class SomeCoolClass implements TemplateLoader {
//other functions here
#Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
Reader reader = delegate.getReader(templateSource, encoding);
try {
String templateText = IOUtils.toString(reader);
return new StringReader(ESCAPE_PREFIX + templateText + ESCAPE_SUFFIX);
} finally {
IOUtils.closeQuietly(reader);
}
}
which is a snippet from the link above. You create the class with the existing templateLoader, and just defer all the required methods to that.
Starting from FreeMarker 2.3.24 no TemplateLoader "hack" is needed anymore. There's a setting called output_format, which specifies if and what escaping is needed. This can be configured both globally, and/or per-template-name-pattern utilizing the template_configurations setting. The recommend way of doing this is even simpler (from the manual):
[...] if the
recognize_standard_file_extensions setting is true (which is the
default with the incompatible_improvements setting set to 2.3.24 or
higher), templates whose source name ends with ".ftlh" gets "HTML"
output format, and those with ".ftlx" get "XML" output format

Resources