How can I apply a filter to a function?

I have a list filter which defines a subset of my tiddlers and a custom function I want to apply only to the tiddlers in the list filter.

What TWiki-fu magic do I need?

Tiddler Commander. You can do almost anything by entering the filter and editing the tiddlers selected.

I’m sure someone will give a better answer but maybe the function operator (or possibly the filter operator or the subfilter operator)?

if I understand your question correctly I have an answer. I may need to return in a few hours.

the topic title is a little odd if you consider a function is a filter. Really you seem to be asking for a compound filter, which most are.

can you give more details or an example?

note there is a difference between a function and one that can be used as a custom filter operator.

1 Like

I thought I’d go for a two pronged attack in my forum posts, one general (this one) and one specific (the PDeck thread). I seem to have failed on both counts!

I have a function (from the Pdeck plugin) which checks the ‘topic’ field in tiddlers tagged ‘question’, counts the instances of tiddlers named in the ‘topic’ field and plonks a button in all tiddlers tagged ‘topic’ with matching tiddlers title.

I’d like to cut out the topic tagging and just plonk the button in all tiddlers which are named in the Question/ Topic field.

I’m afraid this is still confusing, at least for me. (Maybe because I haven’t played with the Problem Deck yet.)

When you talk about “plonking” a button somewhere, is that a one-time thing, Commander-style, where you are making batch changes to your wiki, adding button markup to the selected tiddlers? Or do you want to have some template show a specific button when they’re rendered? Or something else?

You talk about counting instances, but don’t suggest doing anything with that count, instead—I think—plonking a button in some subset of them.

I’m afraid a more detailed explanation seems necessary. By any chance is the wiki you’re working on public?

1 Like

I am afraid I need to second @Scott_Sauyet on this one. I expect its could be clear in your head, but it needs to be so in ours as well.

One imediate responce I may suggest is my filter-pill, a pill rather than a button, which behaves like my reimagin tags but for a given filter, such as in your case;

  • On tiddlers tagged Question
  • counting tiddlers in in the topic (list field)
  • this is where I get lost “and plonks a button in all tiddlers tagged ‘topic’ with matching tiddlers title.”

It sounds like you want a kind of backlinks such that tiddlers named in a question and/or topics will themselfs indicate they are listed elsewhere?

I am confident I can help you do what you want but not until that is clear.

@Ste_W

This is a function:

\function .my-fn() [tag[my-tag]]

Your subject line says you want to apply a filter (e.g. [prefix[ste]]) to the function .my-fn.

Sorry dude, I have no idea what you want to achieve, either. How would you apply that filter to .my-fn?

Did you mean this?

[prefix[ste].my-fn[]]

which is actually the opposite of what you asked for (applying a function to a filter).

Ok… It’s all view templates.

I have a function wot does stuff (and works correctly) and makes a button in correctly tagged tiddlers (Topic would be the tag).
The tiddlers which the function does stuff in are referenced in a field (topic) of other tiddlers tagged question.

I’d like to view template filter so the function automatically attaches itself to tiddlers referenced in the topic field of question tiddlers.

All of this is trying to tweak @Mohammad problem deck.

The tiddlers I want to apply the function to would be <$list filter="[title<currentTiddler>listed[topic]tag[Question]]">

And the function I want to apply to those is

\function topic.filter() [tag[Question]contains:topic<currentTiddler>]
<$list filter=[{!!title}tag[Topic]]>
	<aside class="kk-pdeck-topic-stat">
		<span>Statistics</span>
		<span>Exams: <$count filter="[topic.filter[]get[exam]enlist-input[]unique[]]"/></span>
		<span>
            <$button>
                  <$action-navigate $to={{{ [<currentTiddler>addprefix[Questions for ]] }}} $scroll="yes"/>
Questions:
</$button>
<$count filter="[topic.filter[]]"/></span>

And you can find it at My wiki (should open with the plugin in, the view template pasted above and a topic tiddler. Problem deck can be seen in a tab in the sidebar)

I’m not sure what you mean by “applying” a function to a filter, or vice versa (rather than using a custom function within a longer filter); a function is a filter expression…

It sounds like you want a view template to appear in a set of tiddlers (namely, the set that meets the filter conditions). That’s good and clear.

And the view template (whose contents you pasted into your post) does use the function topic.filter… (Your post seems to treat “the function” as the view-template tiddler’s much longer stretch of widgets, etc. As far as I can tell, topic.filter is just a single-line function \function topic.filter() [tag[Question]contains:topic<currentTiddler>] , and everything after that is just unfolding the view template contents that use that function.)

Could you say how that view template is failing to behave as expected? What is it doing, and what do you want it to do instead?

If you want to use that custom function within other tiddlers (beyond that view template where it’s defined), you just need to add the $:/tags/Global tag.

I think you’re using terminology which is confusing others here. I’d like to try a different approach.

Here’s what I believe the code you’ve shared does:

For any tiddler tagged Topic, it adds an ASIDE node with:

  • The header “Statistics”
  • A count of exams, found by finding all tiddlers tagged Question whose topics field contains the current tiddler, finding all values in their exam list fields, removing duplicates from the results, and counting them
  • A button to open the tiddler Questions for <current tiddler title>

Is that correct? If so, using similar language, can you explain what you’d like it to do instead?

I want the function to do just what it does.

I want it to do it’s stuff automatically on the subset of tiddlers which are named in the topic field of Question tagged tiddler so I don’t have to manually add Topic tag to the tiddlers listed in that aforementioned field.

Can you try replacing it with this version and removing the Topic tag from Velocity and see if it works as you would like?

\function topic.filter() [tag[Question]contains:topic<currentTiddler>]

<$list filter="[subfilter<topic.filter>first[]]" variable="_">
	<aside class="kk-pdeck-topic-stat">
		<span>Statistics</span>
		<span>Exams: <$count filter="[topic.filter[]get[exam]enlist-input[]unique[]]"/></span>
		<span>
            <$button>
				<$action-navigate $to={{{ [<currentTiddler>addprefix[Questions for ]] }}} $scroll="yes"/>
				Questions:
			</$button>
			<$count filter="[topic.filter[]]"/>
		</span>
	</aside>
</$list>

Changes

I reformatted this and added the final closing tags (which TW allows to be optional, but which to my mind make the code much easier to read). These are all minor. The only substantive thing I changed was in the filter of the outer $list widget. Instead of [{!!title}tag[Topic]], I used [subfilter<topic.filter>first[]], where the function topic.filter was defined on the first line and used in two additional places throughout the template.

That topic.filter function finds the tiddlers tagged Question whose topic field includes the title of the current tiddler. For this outer $list guard, we want to see if there are any such questions. So we call that filter and use first[] to run the $list's body only once. We also add a dummy variable so that it doesn’t override currentTiddler. Everything else remains as it was.

More Modern

However, your wiki is using a recent version of TW, which means you can use <% if %> / <% elseif %> / <% else %> / <% endif %>. That makes it a bit easier to write that outer wrapper:

\function topic.filter() [tag[Question]contains:topic<currentTiddler>]

<% if [subfilter<topic.filter>] %>
	<aside class="kk-pdeck-topic-stat">
		<span>Statistics</span>
		<span>Exams: <$count filter="[topic.filter[]get[exam]enlist-input[]unique[]]"/></span>
		<span>
            <$button>
				<$action-navigate $to={{{ [<currentTiddler>addprefix[Questions for ]] }}} $scroll="yes"/>
				Questions:
			</$button>
			<$count filter="[topic.filter[]]"/>
		</span>
	</aside>
<% endif %>

Terminology

Part of the reason we were having a hard time understanding your request is that you were using “function” in a way very different from how TW thinks of them. Other terms were confusing too. Feel free to skip this section, but if you want to understand the issue, here’s my attempt at an explanation:

A function in TW accepts some number of parameters and returns a string. They are written in two ways:

1. Regular function definition

\function name(param1, param2, ...)
    <!-- some filter here -->
\end

2. Single-line function definition

\function name(param1, param2, ...) <!-- some filter here -->

Your code sample includes a single-line function at the top. The rest of the code is not part of that function. But it does invoke that function – twice in your initial version, three times in my update.

So the title “How can I apply a filter to a function?” sounds nonsensical. A function is something you call to get back a value. Applying a filter to it makes no sense.

The important thing to note about the tiddler with that code is the tag $:/tags/ViewTemplate. That is what this block is, a template. (Again, it’s not a function, even though it happens to contain one.) What you’re really trying to do is to change the code that guards whether the remaining contents of this template will appear when your tiddler is rendered. This was a $list widget in your original and my first refactoring, an <% if %> block in my second version. What you’re calling “plonking” a button somewhere, we might call “conditionally rendering” it.

In any case, that’s why we got lost. Please let me know if this works, and if this explanation is clear!

3 Likes

I also found that a little CSS made these statistics much more readable:

aside.kk-pdeck-topic-stat {
  border: 1px solid <<colour pre-border>>;
  padding: .5em;
  margin: 0 0 0 .25em;
}
1 Like

Thank you so much!
That all works and your explanation makes sense.

Thanks for unpicking my question. (I’d thought the entire thing was the function…) :smiley:

2 Likes

@Ste_W I just want to point out there are other ways to use and write “functions”, I am pointing this out because there is more to learn in this space. For example when you reference a “function as a variable” it is replaced with the first result of the function.

Thus without testing you should be able to reduce your filter in the list widget;

<$list filter="[subfilter<topic.filter>first[]]" variable="_">

simply with

<$list filter=<<topic.filter>> variable="_">

But of course when used in the %if it myust be a filter.

A key value of functions is they are evaluated and can thus influence the TiddlyWiki scripts before the final render. Rather than needing wikify.

1 Like