Filters and transclusions interact in two useful ways:
- We can transclude the result of a filter.
- We can transclude the value of a variable or tiddler field into a filter.
Transcluding the result of a filter
As we know, we can transclude the text
field of a tiddler by placing its title in {{double curly braces}}
. We can transclude the result of a filter expression by placing it in {{{triple curly braces}}}
; this is sometimes called a filtered transclusion. Here's a filtered transclusion of the names of the alphabetically first five sections in this book:
{{{ [all[shadows+tiddlers]tag[Section]first[5]] }}}
(The all[tiddlers+shadows]
step is required here and in many live examples to come because of the way Grok TiddlyWiki is packaged; in your own wiki, you wouldn't need this step. If you're too curious to wait for the explanation, jump ahead to Shadow Tiddlers.)
The spaces directly inside the curly braces are not required, but they're highly recommended: if you leave them out, there are so many brackets next to each other that it is nearly impossible to tell whether you've inserted the right number of them.
Let's open up the MeetingList
tiddler in our example wiki and create a list of meetings using a similar filter:
{{{ [tag[Meeting]] }}}
You'll want to put a blank line above and below this line – otherwise, all the titles will be run together (this is the block-versus-inline-mode thing again).
This is a really quick-and-dirty way of creating a list which can come in handy occasionally, but this syntax is most commonly used when we want to use a filter to create or manipulate some text and include it somewhere, either directly in the body of a tiddler or as an attribute of a widget or HTML tag. For instance, suppose we want to display a count of how many meetings we currently have notes on:
There are {{{ [tag[Meeting]count[]] }}} meetings in this wiki.
If you tweak the filter in your wiki to match this, you'll notice something a little odd, though – supposing your wiki currently has 2 meetings, 2 is a link, to a nonexistent tiddler called 2
. What's up with that?
Well, since filters are mostly designed to work with tiddler titles, when you get the output of a filter, TiddlyWiki assumes each item in the output is a tiddler, so it tries to be helpful and link it. Certain filter operators, however – like count[]
, or get[]
– will break this assumption. Fortunately, if you're fussy about having pointless links show up, overriding the default is easy – we simply use the $text
widget, which tells TiddlyWiki that we want something to be treated as plain text rather than wikitext:
There are <$text text={{{ [tag[Meeting]count[]] }}} /> meetings in this wiki.
Only the first output tiddler will be transcluded into an attribute
You might be tempted to extrapolate the above example to create a list of meetings that aren't links, like this:
<$text text={{{ [tag[Meeting]] }}}/>
However, if you try this, you'll find that only one meeting shows up. That's because when you transclude the result of a filter expression as a value of an attribute, unlike when you place it directly in wikitext, only the first output tiddler is kept.
The rationale for this is simply that it's rarely useful to do anything else. If TiddlyWiki passed a list of meetings directly to the $text
widget, you would just get a long string of meeting names separated by spaces. If you actually want to list all the meetings as text, or as a bulleted list of text names, you would use a $list
widget instead so you could specify what each item should look like. With the actual behavior, if a filter accidentally returns more than one item, at least the attribute will get a value that actually represents a real output tiddler, rather than a made-up value that combines several of them.
Nevertheless, it's important to be aware of this behavior, or you may find yourself very confused on occasion.
Transcluding inside the value of an attribute
In Using Variables as Attributes, we learned that you can combine variables and constant text into the value of an attribute using the substituted attribute value syntax, like this:
<$widget attribute=`text and $(variable)$`/>
Similarly, you can combine the result of a filter and constant text, by replacing the parentheses with braces and the variable name with a filter expression:
<$widget attribute=`text and ${ [filter-expression[]] }$`/>
Transcluding things into a filter
The dynamic lists we've created so far are nice, but they've had a significant limitation: no part of the filter can change unless we go in and edit it. Often, we might like to be able to make part of the filter a value that changes, like a field or a variable.
Let's think back to the exercise where we included Jane's manager's phone number in the JaneDoe
tiddler (we've since moved this bit onto the ContactInformationTemplate
). Suppose that instead of the phone number of the person's manager, we want to list the names and phone numbers of all people listed in the family
field.
At first, this seems pretty straightforward:
<ul>
<$list filter="some filter">
<li>{{!!title}}: {{!!phone}}</li>
</$list>
</ul>
But what do we put as the filter to retrieve the contents of the family
field? It's tempting to try [all[current]get[family]]
, but that retrieves the entire text of the family
field as a single input tiddler, which means it won't work properly if there is more than one family member in the list.
We can use the enlist
filter operator to turn a tiddler list into a series of input tiddlers within the filter expression, but we have to pass it the tiddler list as a parameter, so we can't use get[]
. And remember that we need to put the tiddler list in the family
field of the current tiddler into that parameter – we can't directly name the tiddler (e.g., JaneDoe
), since this snippet would then only work in Jane's tiddler.
To achieve this, we can replace the square brackets around the parameter with {curly braces}
, and place a field transclusion inside:
<ul>
<$list filter="[enlist{!!family}]">
<li>{{!!title}}: {{!!phone}}</li>
</$list>
</ul>
Notice that there is only one set of curly braces in the filter expression, rather than two, just like there is only one set of square brackets in their place if you're providing a value that doesn't change.
Similarly, if the value we wanted to use was in a variable rather than a field, we could use single angle brackets:
<ul>
<$let familyfield={{!!family}}>
<$list filter="[enlist<familyfield>]">
<li>{{!!title}}: {{!!phone}}</li>
</$list>
</$set>
</ul>
You can also transclude the result of procedure calls with parameters using this syntax. However, this might not work quite the way you hope, because, just like if you were using this procedure call as the value of an attribute, wikitext won't be processed inside the filter, so you may end up with unexpanded variable transclusions in the filter pipeline:
\procedure partial-name(suffix) Tiddler <<suffix>>
{{{ [<partial-name "Forty-Two">] }}}
In chapter 6, we'll learn how Macros and Wikification can make this syntax consistently useful.
Curly braces or angle brackets can be used by themselves, not preceded by an operator, to directly introduce an arbitrary value into the filter pipeline. This is the equivalent of specifying a literal title with square brackets:
{{{ [[abc]addsuffix[def]] }}}
<$let myVariable="abc">
{{{ [<myVariable>addsuffix[def]] }}}
</$let>
Sometimes a filter parameter that is transcluded into the filter with {braces}
or <angle brackets>
is called a soft parameter, in contrast to an unchanging hard parameter specified with [square brackets]
.
Side note
Actually, if we weren't trying to use the above example as a general example, there's an even easier way to make the family list:
<ul>
<$list filter={{!!family}}>
<li>{{!!title}}: {{!!phone}}</li>
</$list>
</ul>
That may look weird right now, but when we get to Multi-Run Filters in the next chapter, you'll understand why this works. For now, this is more a curiosity than anything else; it certainly won't work in all situations in which you might want to substitute a field or variable value into a filter.
Exercises
Create a list of all tiddlers that contain the title of the wiki.
- The current title of the wiki can be found in the tiddler named
$:/SiteTitle
. - The
search
filter operator is used to find tiddlers that contain some arbitrary text.
Edit the ContactInformationTemplate
so that a contact's family members each get their own bullet point, nested underneath the Family
bullet point, listing their name and phone number, like this:
- Family:
- JohnDoe: 888-555-9999
- EmilyDoe: 888-555-1111
Tip: You'll need to use HTML for the inner bulleted list, as wikitext lists can't be interleaved successfully with $list
widgets. While it's possible to make everything show up correctly while still writing the outer bulleted list in wikitext, if you're struggling with the formatting, it may be easier to switch the outer list to an HTML list as well.
As a reminder, to nest lists in HTML, put another <ul>
opening tag inside an <li>
tag.
In Ex:ProcedureAdjacency back in Using Variables as Attributes, we found that this attempt to use a simple variable to compose a Wikipedia link didn't work:
<$let wikipedia="https://en.wikipedia.org/wiki/">
<<wikipedia>>Aardvark
</$let>
Fix this example by replacing the <<wikipedia>>Aardvark
line with an a
element using a {{{ filtered transclusion }}}
.
Tip: The filter operator addsuffix
will come in handy.
Make the solution of the previous exercise into a separate WikipediaLinkTemplate
tiddler that can be transcluded, so that it can be used for creating links to more things than just aardvarks. As we learned in Ex:VariableTransclusion, variable values will carry across transclusion boundaries, so refer to the value of a variable called articleName
to decide what article to link to.
While you're at it, make this template more robust by getting the value https://en.wikipedia.org/wiki/
from another tiddler; this way, we can reference the base URL of Wikipedia from other places, and only have to update it in one place if it changes.
Modify the template you created in Ex:WikipediaLinkTemplate so that if the articleName
variable is not defined, the article name will instead be taken from the articlename
field of the current tiddler.
Tip: The else
filter operator, which adds a constant string to the pipeline if there are no input tiddlers, will be useful here. You will also need to put !is[blank]
before the else
operator – we'll explain why once you've completed this exercise.
Create a tiddler called WikiStatistics
that shows the following pieces of information in a bulleted list:
- How many contacts are in the wiki.
- How many unique tiddlers are linked from meetings. (It will be unique without having to do anything special, so don't panic if you think you don't know how to make it unique.)
- What percentage of non-system tiddlers in the wiki are contacts, to three digits of precision (e.g., 10.2%, or 1.55%).
To complete the last one, you'll need to review the list of Mathematics Operators on the filter operators manual page.
go to answer