This is a stripped-down version of a single section of Grok TiddlyWiki, optimized for fast loading and readability by search engines. Some features are missing.

For the full Grok TiddlyWiki experience, please visit the wiki version of this page.

Filters and Transclusions

18th August 2021 at 4:03pm

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.

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? We can't directly name the tiddler we want to retrieve the field from (e.g., JaneDoe), since this snippet would then only work in Jane's tiddler. Instead, we need to refer to a value on the current tiddler somehow. Our first thought might be to define a macro, like we did in the manager exercise:

\define myfilt(people)
[enlist[$people$]]
\end

The enlist filter operator takes a list field, with values separated by spaces or wrapped in [[double square brackets]], and splits it apart into individual tiddler names. If we left enlist out, then we'd be looking for a tiddler called JohnDoe EmilyDoe (the exact text that's in the family field of the JaneDoe tiddler), instead of the two tiddlers JohnDoe and EmilyDoe (what we meant).

OK, now let's just pass the results of calling that macro to the $list widget:

<$list filter=<<myfilt ...>> >

Wait a sec…how do we call myfilt with the value of the family field? <<myfilt {{!!family}}>> sounds nice, but isn't valid. We have to use a $macrocall widget to pass transclusions as parameters to a macro. But sadly, this isn't valid syntax either:

<$list filter=<$macrocall $name="myfilt" people={{!!family}}/>>

You can't put a widget inside an attribute of another widget. We could turn the result of the macro call into a variable that we could pass to the filter attribute of the $list widget:

<$set name=filtersnippet value=...

…Wait, same problem! Dang it!

There is in fact a way to solve this problem with macros; we'll learn how to do it in Using Variables in Macros. But it should be clear that using a macro here is a whole lot more work than we want to deal with. All we really want is to pass the contents of the family field into the enlist operator.

Here's the syntax that allows us to do that.

<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.

If the value we wanted to use was in a variable rather than a tiddler field, we could use single angle brackets:

<ul>
    <$set name="familyfield" value={{!!family}}>
        <$list filter="[enlist<familyfield>]">
            <li>{{!!title}}: {{!!phone}}</li>
        </$list>
    </$set>
</ul>

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]] }}}

<$set name="myVariable" value="abc">
    {{{ [<myVariable>addsuffix[def]] }}}
</$set>

Lastly, you can also transclude the result of macro calls with constant parameters into a filter:

\define partial-name(suffix) Tiddler $suffix$

{{{ [<partial-name "Forty-Two">] }}}

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, there's an even easier if not immediately intuitive way to make the family list, and this would likely be what you'd want to do in a real-world situation:

<ul>
    <$list filter={{!!family}}>
        <li>{{!!title}}: {{!!phone}}</li>
    </$list>
</ul>

That may look weird right now, but when we get to Multi-Run Filters, 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, so what we learned above is still important.

Exercises

Exercise: (m) [Ex:TiddlersContainingWikiTitle]

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.
go to answer

Exercise: (m) [Ex:AllFamilyInformation]

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.

go to answer

Exercise: (m) [Ex:WikipediaLinkWithoutMacro]

In Ex:MacroAdjacency within the Macros section, we found that this attempt to use a simple variable instead of a macro to compose a Wikipedia link didn't work:

<$set name="wikipedia" value="https://en.wikipedia.org/wiki/">
    <<wikipedia>>Aardvark
</$set>

We now have the tools needed to accomplish this without a macro. Your solution should display a link to the Aardvark article which has been built from the wikipedia variable shown above and the constant part Aardvark, but without using a macro.

  • You will need the filter operator addsuffix.
  • You'll need to use the HTML tag a, which creates an anchor, including a link. The form of this tag is as follows:
<a href="the URL">the link text</a>
go to answer

Exercise: (m) [Ex:WikipediaLinkTemplate]

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.

go to answer

Exercise: (m) [Ex:DefaultToField]

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.

  • Note the lowercase n – field names can't contain uppercase letters.
  • 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.
go to answer

Exercise: (M) [Ex:WikiStatistics]

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

Takeaways

Takeaways are not available in the static version of Grok TiddlyWiki. Visit the wiki version of this page to study takeaways.

↑ 4: Variables, Macros, and Transclusions