blob: ba21ff189d3a18a303b2ffd9b8aa3250182bdea7 [file] [log] [blame]
<!doctype html>
<!-- Generated by FreeMarker/Docgen from DocBook -->
<html lang="en" class="page-type-section">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>Defining your own directives - FreeMarker Manual</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="format-detection" content="telephone=no">
<meta property="og:site_name" content="FreeMarker Manual">
<meta property="og:title" content="Defining your own directives">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="http://example.com/dgui_misc_userdefdir.html">
<link rel="canonical" href="http://example.com/dgui_misc_userdefdir.html">
<link rel="icon" href="favicon.png" type="image/png">
<link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1594338517553">
</head>
<body itemscope itemtype="https://schema.org/Code">
<meta itemprop="url" content="http://example.com/">
<meta itemprop="name" content="FreeMarker Manual">
<!--[if lte IE 9]>
<div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please use a modern browser to view this website.</div>
<![endif]--><div class="header-top-bg"><div class="site-width header-top"><a class="logo" href="http://example.com" role="banner"> <img itemprop="image" src="logo.png" alt="My Logo">
</a></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">FreeMarker Manual</a><div class="navigation-header"></div></div><div class="site-width breadcrumb-row"><ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="index.html"><span itemprop="name">FreeMarker Manual</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="dgui.html"><span itemprop="name">Template Author&#39;s Guide</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="dgui_misc.html"><span itemprop="name">Miscellaneous</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="dgui_misc_userdefdir.html"><span itemprop="name">Defining your own directives</span></a></li></ul><div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul class="bookmark-list"><li><a href="alphaidx.html">Index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="ref.html">Reference</a></li><li><a href="app_faq.html">FAQ</a></li><li><a href="preface.html#test_target">Bőregér</a></li></ul></div></div></div> <div class="main-content site-width">
<div class="content-wrapper no-toc">
<div id="table-of-contents-wrapper" class="col-left">
</div>
<div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="dgui_misc.html"><span>Previous</span></a><a class="paging-arrow next" href="dgui_misc_var.html"><span>Next</span></a></div><div class="title-wrapper">
<h1 class="content-header header-section1" id="dgui_misc_userdefdir" itemprop="headline">Defining your own directives</h1>
</div></div><div class="page-menu">
<div class="page-menu-title">Page Contents</div>
<ul><li><a class="page-menu-link" href="#autoid_21" data-menu-target="autoid_21">Basics</a></li><li><a class="page-menu-link" href="#autoid_22" data-menu-target="autoid_22">Parameters</a></li><li><a class="page-menu-link" href="#autoid_23" data-menu-target="autoid_23">Nested content</a></li><li><a class="page-menu-link" href="#dgui_misc_userdefdir_loopvar" data-menu-target="dgui_misc_userdefdir_loopvar">Macros with loop variables</a></li><li><a class="page-menu-link" href="#autoid_24" data-menu-target="autoid_24">More about user-defined directives and macros</a></li></ul> </div><p>As far as template authors are concerned, user-defined
directives can be defined using the <code class="inline-code">macro</code>
directive. <span class="marked-for-programmers">Java programmers who want to
implement directives in Java Language, rather than in a template,
should use
<code class="inline-code">freemarker.template.TemplateDirectiveModel</code> (see
<a href="pgui_datamodel_directive.html">more
here...</a>).</span></p>
<h2 class="content-header header-section2" id="autoid_21">Basics</h2>
<p>A macro is a template fragment associated with a variable. You
can use that variable in your template as a user-defined directive,
so it helps in repetitive tasks. For example, this creates a macro
variable that prints a big ``Hello Joe!&#39;&#39;:</p>
<div class="code-wrapper"><pre class="code-block code-template"><strong>&lt;#macro greet&gt;</strong>
&lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;
<strong>&lt;/#macro&gt;</strong></pre></div>
<p>The <code class="inline-code">macro</code> directive itself does not print
anything; it just creates the macro variable, so there will be a
variable called <code class="inline-code">greet</code>. Things between the
<code class="inline-code">&lt;#macro greet&gt;</code> and
<code class="inline-code">&lt;/#macro&gt;</code> (called <strong>macro definition body</strong>) will be executed only
when you use the variable as directive. You use user-defined
directives by writing <code class="inline-code">@</code> instead of
<code class="inline-code">#</code> in the FTL tag. Use the variable name as the
directive name. Also, the <a href="gloss.html#gloss.endTag">end-tag</a> for user-defined directives is
mandatory. So you use <code class="inline-code">greet</code> like this:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet&gt;&lt;/@greet&gt;</pre></div>
<p>But since
<code class="inline-code">&lt;<em class="code-color">anything</em>&gt;&lt;/<em class="code-color">anything</em>&gt;</code>
is equivalent with
<code class="inline-code">&lt;<em class="code-color">anything</em>/&gt;</code> you
should use this shorter form (that is familiar for you if you know
<a href="gloss.html#gloss.XML">XML</a>):</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet/&gt;</pre></div>
<p>This will print:</p>
<div class="code-wrapper"><pre class="code-block code-output"> &lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;
</pre></div>
<p>But macros can do much more, since the thing between
<code class="inline-code">&lt;#macro <em class="code-color">...</em>&gt;</code> and
<code class="inline-code">&lt;/#macro&gt;</code> is a template fragment, thus it
can contain interpolations
(<code class="inline-code">${<em class="code-color">...</em>}</code>) and FTL tags
(e.g. <code class="inline-code">&lt;#if
<em class="code-color">...</em>&gt;<em class="code-color">...</em>&lt;/#if&gt;</code>).</p>
<div class="callout note">
<strong class="callout-label">Note:</strong>
<p>Programmers will say on
<code class="inline-code">&lt;@<em class="code-color">...</em>&gt;</code> that
you <strong>call</strong> the macro.</p>
</div>
<h2 class="content-header header-section2" id="autoid_22">Parameters</h2>
<p>Let&#39;s improve the <code class="inline-code">greet</code> macro so it can use
arbitrary name, not only ``Joe&#39;&#39;. For this purpose you can use
<strong>parameters</strong>. You define the
parameters after the name of the macro in the
<code class="inline-code">macro</code> directive. Here we define one parameter for
the <code class="inline-code">green</code> macro,
<code class="inline-code">person</code>:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro greet <strong>person</strong>&gt;
&lt;font size=&quot;+2&quot;&gt;Hello <strong>${person}</strong>!&lt;/font&gt;
&lt;/#macro&gt;</pre></div>
<p>and then you can use this macro as:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet <strong>person=&quot;Fred&quot;</strong>/&gt; and &lt;@greet <strong>person=&quot;Batman&quot;</strong>/&gt;</pre></div>
<p>which is similar to HTML syntax. This will print:</p>
<div class="code-wrapper"><pre class="code-block code-output"> &lt;font size=&quot;+2&quot;&gt;Hello <strong>Fred</strong>!&lt;/font&gt;
and &lt;font size=&quot;+2&quot;&gt;Hello <strong>Batman</strong>!&lt;/font&gt;
</pre></div>
<p>As you can see, the actual value of the macro parameter is
accessible in the macro definition body as a variable
(<code class="inline-code">person</code>). As with <a href="gloss.html#gloss.predefinedDirective">predefined directives</a>,
the value of a parameter (the right side of <code class="inline-code">=</code>) is
an <a href="dgui_template_exp.html">FTL expression</a>. Thus,
unlike with HTML, the quotation marks around
<code class="inline-code">&quot;Fred&quot;</code> and <code class="inline-code">&quot;Batman&quot;</code> are not
optional. <code class="inline-code">&lt;@greet person=Fred/&gt;</code> would mean
that you use the value of variable <code class="inline-code">Fred</code> for the
<code class="inline-code">person</code> parameter, rather than the string
<code class="inline-code">&quot;Fred&quot;</code>. Of course parameter value need not be a
string, it can be number, boolean, hash, sequence, ...etc., also you
can use complex expression on the left side of <code class="inline-code">=</code>
(e.g. <code class="inline-code">someParam=(price + 50)*1.25</code>).</p>
<p>User-defined directives can have multiple parameters. For
example, add a new parameter <code class="inline-code">color</code>:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro greet person <strong>color</strong>&gt;
&lt;font size=&quot;+2&quot; color=&quot;${color}&quot;&gt;Hello ${person}!&lt;/font&gt;
&lt;/#macro&gt;</pre></div>
<p>and then you can use this macro like:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet person=&quot;Fred&quot; color=&quot;black&quot;/&gt;</pre></div>
<p>The order of parameters is not important, so this is
equivalent with the previous:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet color=&quot;black&quot; person=&quot;Fred&quot;/&gt;</pre></div>
<p>When you call the macro, you can use only parameters that you
have defined in the <code class="inline-code">macro</code> directive (in this
case: <code class="inline-code">person</code> and <code class="inline-code">color</code>). So if
you try <code class="inline-code">&lt;@greet person=&quot;Fred&quot; color=&quot;black&quot;
background=&quot;green&quot;/&gt;</code> then you will get an error, since
you haven&#39;t mentioned parameter <code class="inline-code">background</code> in the
<code class="inline-code">&lt;#macro
<em class="code-color">...</em>&gt;</code>.</p>
<p>Also, you must give value for all parameters that you have
defined for the macro. So if you try <code class="inline-code">&lt;@greet
person=&quot;Fred&quot;/&gt;</code> then you will get an error, since you
forgot to specify the value of <code class="inline-code">color</code>. However, it
often happens that you would specify the same value for a parameter
in most cases, so you want to specify the value only when you want a
different value for it than the usual. This can be achieved if you
specify the parameter in the <code class="inline-code">macro</code> directive as
<code class="inline-code"><em class="code-color">param_name</em>=<em class="code-color">usual_value</em></code>.
For example, you want to use <code class="inline-code">&quot;black&quot;</code> for
<code class="inline-code">color</code> if you don&#39;t specify value for that
parameter when you use the <code class="inline-code">greet</code>
directive:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro greet person color<strong>=&quot;black&quot;</strong>&gt;
&lt;font size=&quot;+2&quot; color=&quot;${color}&quot;&gt;Hello ${person}!&lt;/font&gt;
&lt;/#macro&gt;</pre></div>
<p>Now <code class="inline-code">&lt;@greet person=&quot;Fred&quot;/&gt;</code> is OK,
since it is equivalent with <code class="inline-code">&lt;@greet person=&quot;Fred&quot;
color=&quot;black&quot;/&gt;</code>, thus the value of
<code class="inline-code">color</code> parameter is known. If you want
<code class="inline-code">&quot;red&quot;</code> for <code class="inline-code">color</code>, then you
write <code class="inline-code">&lt;@greet person=&quot;Fred&quot; color=&quot;red&quot;/&gt;</code>,
and this value will override the usual value specified with the
<code class="inline-code">macro</code> directive, so the value of
<code class="inline-code">color</code> parameter will be
<code class="inline-code">&quot;red&quot;</code>.</p>
<p>Also, it is important to realize that -- according to the
already explained <a href="dgui_template_exp.html">FTL expression
rules</a> -- <code class="inline-code">someParam=foo</code> and
<code class="inline-code">someParam=&quot;${foo}&quot;</code> are very different. In the
fist case, you use the value of variable <code class="inline-code">foo</code> as
the value of the parameter. In the second case, you use a <a href="dgui_template_exp.html#dgui_template_exp_stringop_interpolation">string literal
with interpolation</a>, so the value of the parameter will be a
string -- in this case, the value of <code class="inline-code">foo</code> rendered
to text -- regardless of the type (as number, date, etc.) of
<code class="inline-code">foo</code>. Or, another example:
<code class="inline-code">someParam=3/4</code> and
<code class="inline-code">someParam=&quot;${3/4}&quot;</code> are different. If the
directive wants a numerical value for <code class="inline-code">someParam</code>,
it will not like the second variation. Do not exchange these.</p>
<p>A very important aspect of macro parameters is that they are
local variables. For more information about local variables please
read: <a href="dgui_misc_var.html">Defining variables in the template</a></p>
<h2 class="content-header header-section2" id="autoid_23">Nested content</h2>
<p>Custom directive can have nested content, similarly as
predefined directives like <code class="inline-code">&lt;#if
<em class="code-color">...</em>&gt;<em class="code-color">nested
content</em>&lt;/#if&gt;</code> can have. For example,
this creates a macro that draws borders around its nested
content:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro border&gt;
&lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;
<strong>&lt;#nested&gt;</strong>
&lt;/tr&gt;&lt;/td&gt;&lt;/table&gt;
&lt;/#macro&gt;</pre></div>
<p>The <code class="inline-code">&lt;#nested&gt;</code> directive executes the
template fragment between the start-tag and end-tags of the
directive. So if you do this:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@border&gt;The bordered text&lt;/@border&gt;</pre></div>
<p>the output will be:</p>
<div class="code-wrapper"><pre class="code-block code-output"> &lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;
The bordered text
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
</pre></div>
<p>The <code class="inline-code">nested</code> directive can be called for
multiple times, for example:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro do_thrice&gt;<strong>
&lt;#nested&gt;
&lt;#nested&gt;
&lt;#nested&gt;</strong>
&lt;/#macro&gt;
&lt;@do_thrice&gt;
Anything.
&lt;/@do_thrice&gt;</pre></div>
<p>will print:</p>
<div class="code-wrapper"><pre class="code-block code-output"> Anything.
Anything.
Anything.</pre></div>
<p>If you don&#39;t use the nested directive, then the nested content
will not be executed. Thus, if you accidentally use the
<code class="inline-code">greet</code> directive like this:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@greet person=&quot;Joe&quot;&gt;
Anything.
&lt;/@greet&gt;</pre></div>
<p>then FreeMarker will not see this as an error, and simply
prints:</p>
<div class="code-wrapper"><pre class="code-block code-output">&lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;</pre></div>
<p>and the nested content will be ignored, since the
<code class="inline-code">greet</code> macro never uses <code class="inline-code">nested</code>
directive.</p>
<p>The nested content can be anything that is valid FTL,
including other user-defined directives. Thus this is OK:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@border&gt;
&lt;ul&gt;
&lt;@do_thrice&gt;
&lt;li&gt;&lt;@greet person=&quot;Joe&quot;/&gt;
&lt;/@do_thrice&gt;
&lt;/ul&gt;
&lt;/@border&gt;</pre></div>
<p>and will print:</p>
<div class="code-wrapper"><pre class="code-block code-output"> &lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;&lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;
&lt;li&gt;&lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;
&lt;li&gt;&lt;font size=&quot;+2&quot;&gt;Hello Joe!&lt;/font&gt;
&lt;/ul&gt;
&lt;/tr&gt;&lt;/td&gt;&lt;/table&gt;</pre></div>
<p>The <a href="dgui_misc_var.html">local variables</a> of a
macro are not visible in the nested content. Say, this:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro repeat count&gt;
&lt;#local y = &quot;test&quot;&gt;
&lt;#list 1..count as x&gt;
${y} ${count}/${x}: &lt;#nested&gt;
&lt;/#list&gt;
&lt;/#macro&gt;
&lt;@repeat count=3&gt;${y!&quot;?&quot;} ${x!&quot;?&quot;} ${count!&quot;?&quot;}&lt;/@repeat&gt;</pre></div>
<p>will print this:</p>
<div class="code-wrapper"><pre class="code-block code-output"> test 3/1: ? ? ?
test 3/2: ? ? ?
test 3/3: ? ? ?</pre></div>
<p>because the <code class="inline-code">y</code>, <code class="inline-code">x</code> and
<code class="inline-code">count</code> are the local (private) variables of the
macro, and are not visible from outside the macro definition.
Furthermore, a different set of local variables is used for each
macro call, so this will not cause confusion:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro test foo&gt;${foo} (&lt;#nested&gt;) ${foo}&lt;/#macro&gt;
&lt;@test foo=&quot;A&quot;&gt;&lt;@test foo=&quot;B&quot;&gt;&lt;@test foo=&quot;C&quot;/&gt;&lt;/@test&gt;&lt;/@test&gt;</pre></div>
<p>and will print this:</p>
<div class="code-wrapper"><pre class="code-block code-output">A (B (C () C) B) A</pre></div>
<h2 class="content-header header-section2" id="dgui_misc_userdefdir_loopvar">Macros with loop variables</h2>
<p>Predefined directives like <code class="inline-code">list</code> can use
so-called loop variables; you should read <a href="dgui_misc_var.html">Defining variables in the template</a> to understand loop variables.</p>
<p>User-defined directives can also have loop variables. For
example, let&#39;s extend the <code class="inline-code">do_thrice</code> directive of
the earlier examples so it exposes the current repetition number as
a loop variable. As with the predefined directives (as
<code class="inline-code">list</code>) the <em>name</em> of loop
variables is given when you call the directive (as
<code class="inline-code">foo</code> in <code class="inline-code">&lt;#list foos as
foo&gt;<em class="code-color">...</em>&lt;/#list&gt;</code>),
while the <em>value</em> of the variables is set by the
directive itself.</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro do_thrice&gt;
&lt;#nested <strong>1</strong>&gt;
&lt;#nested <strong>2</strong>&gt;
&lt;#nested <strong>3</strong>&gt;
&lt;/#macro&gt;
&lt;@do_thrice <strong>; x</strong>&gt; &lt;#-- user-defined directive uses &quot;;&quot; instead of &quot;as&quot; --&gt;
${<strong>x</strong>} Anything.
&lt;/@do_thrice&gt;</pre></div>
<p>This will print:</p>
<div class="code-wrapper"><pre class="code-block code-output"> 1 Anything.
2 Anything.
3 Anything.
</pre></div>
<p>The syntactical rule is that you pass the actual value of the
loop variable for a certain &quot;loop&quot; (i.e. repetition of the nested
content) as the parameter of <code class="inline-code">nested</code> directive (of
course the parameter can by arbitrary expression). The name of the
loop variable is specified in the user-defined directive open tag
(<code class="inline-code">&lt;@...&gt;</code>) after the parameters and a
semicolon.</p>
<p>A macro can use more the one loop variable (the order of
variables is significant):</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;#macro repeat count&gt;
&lt;#list 1..count as x&gt;
&lt;#nested <strong>x, x/2, x==count</strong>&gt;
&lt;/#list&gt;
&lt;/#macro&gt;
&lt;@repeat count=4 ; <strong>c, halfc, last</strong>&gt;
${<strong>c</strong>}. ${<strong>halfc</strong>}&lt;#if <strong>last</strong>&gt; Last!&lt;/#if&gt;
&lt;/@repeat&gt;</pre></div>
<p>The output will be:</p>
<div class="code-wrapper"><pre class="code-block code-output"> 1. 0.5
2. 1
3. 1.5
4. 2 Last!
</pre></div>
<p>It is not a problem if you specify different number of loop
variables in the user-defined directive start-tag (that is, after
the semicolon) than with the <code class="inline-code">nested</code> directive. If
you specify less loop variables after the semicolon, then simply you
will not see the last few values that the <code class="inline-code">nested</code>
directive provides, since there is no loop variable to hold those
values. So these are all OK:</p>
<div class="code-wrapper"><pre class="code-block code-template">&lt;@repeat count=4 ; <strong>c, halfc, last</strong>&gt;
${c}. ${halfc}&lt;#if last&gt; Last!&lt;/#if&gt;
&lt;/@repeat&gt;
&lt;@repeat count=4 ; <strong>c, halfc</strong>&gt;
${c}. ${halfc}
&lt;/@repeat&gt;
&lt;@repeat count=4&gt;
Just repeat it...
&lt;/@repeat&gt;</pre></div>
<p>If you specify more variables after the semicolon than with
the <code class="inline-code">nested</code> directive, then the last few loop
variables will not be created (i.e. will be undefined in the nested
content).</p>
<h2 class="content-header header-section2" id="autoid_24">More about user-defined directives and macros</h2>
<p>Now you may read the relevant parts of the FreeMarker
Reference:</p>
<ul>
<li>
<a href="ref_directive_userDefined.html#ref.directive.userDefined">user-defined
directive call</a>
</li>
<li>
<a href="ref_directive_macro.html#ref.directive.macro"><code>macro</code>
directive</a>
</li>
</ul>
<p>You can define methods in FTL as well, see <a href="ref_directive_function.html#ref.directive.function">the <code>function</code>
directive</a>.</p>
<p>Also, you may interested in namespaces: <a href="dgui_misc_namespace.html">Namespaces</a>. Namespaces help you to organize
and reuse your commonly used macros.</p>
<div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="dgui_misc.html"><span>Previous</span></a><a class="paging-arrow next" href="dgui_misc_var.html"><span>Next</span></a></div></div></div></div> </div>
</div>
<div class="site-footer"><div class="site-width"><div class="footer-bottom"> <p class="last-generated">
Last generated:
<time itemprop="dateModified" datetime="2020-07-09T23:48:37Z" title="Thursday, July 9, 2020 11:48:37 PM GMT">2020-07-09 23:48:37 GMT</time> </p>
<p class="copyright">
© <span itemprop="copyrightYear">1999</span>–2020
<a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a> </p>
</div></div></div></body>
</html>