I want a tiddler to be used as a UI for others to list tiddlers with some tags they put in a text box and exclude other tiddlers that they put in another. I have a method that works for single tags but I am stuck when it comes to multiple tags. Help would be appreciated please - here is what I have so far:-
<$edit-text field=“include” default="" placeholder=“include tags”/>
<$edit-text field=“exclude” default="" placeholder=“exclude tags”/>
<$list filter="[tag{!!include}]-[tag{!!exclude}]">
<$transclude tiddler={{tiddlertitle}}/> <$link/>
</$list>
There is very likely more than one way to write a filter expression for this, but the first that came to my mind is to use a subfilter that takes a tags list as input and generates a title selection of all tiddlers that have at least one of the tags as output:
<$edit-text tiddler="$:/temp/includetags" placeholder="include tags" tag="input"/>
<$edit-text tiddler="$:/temp/excludetags" placeholder="exclude tags" tag="input"/>
<$let subfilter="[listed[tags]]">
<ul>
<$list filter="""
[enlist{$:/temp/includetags}subfilter<subfilter>]
-[enlist{$:/temp/excludetags}subfilter<subfilter>]
"""
>
<li><$link /></li>
</$list>
</ul>
</$let>
Maybe there is a shorter way to write this that does not involve a subfilter.
There’s also a reason I replaced the field references in your example with temp tiddlers. This change improves performance, as it avoids updates to (and subsequent refreshes of) the tiddler that the edit widgets are part of.
Give this a try:
<$edit-text field=include default="" placeholder="include tags"/>
<$edit-text field=exclude default="" placeholder="exclude tags"/>
<$set name=included filter="[enlist{!!include}] :map:flat[all[tiddlers]tag<currentTiddler>]">
<$set name=excluded filter="[enlist{!!exclude}] :map:flat[all[tiddlers]tag<currentTiddler>]">
<$list filter="[enlist<included>] -[enlist<excluded>]"><$link/><br/></$list>
Notes:
- The two
$set widgets build lists of tiddler titles to be included and excluded, respectively.
- The
:map:flat[...] filter run basically says: "for each tag value in the !!include or !!exclude field, get all tiddlers that have that tag value.
- The
$list widget then combines these calculated lists to output the included titles while removing the excluded titles
- It avoids using the
listed[tags] operator, which will only work with tags that actually exist as tiddlers and that have list fields defined.
-e
The complexity of the answers so far has me wondering if I’m missing something, but here’s what I’d try (modified from Eric’s code):
<$edit-text field=include default="" placeholder="include tags"/>
<$edit-text field=exclude default="" placeholder="exclude tags"/>
<$list filter="[enlist{!!include}tagging[]] -[enlist{!!exclude}tagging[]] +[sort[]]"><$link/><br/></$list>
Since all of the suggestions you’ve received so far involve the enlist operator, I’ll also note that you’ll need to enter tags in title list format, e.g. [[Filter Operators]] [[Tag Operators]]. If your users aren’t familiar with this convention, you might consider replacing the $edit-text widgets with the <<tag-picker>> macro, which would give them a filterable dropdown of existing tags like the one used to add tags to a tiddler:
''Include tags:''
<$list filter="[enlist{!!include}]"><<tag>></$list>
<<tag-picker tagField:"include">>
''Exclude tags:''
<$list filter="[enlist{!!exclude}]"><<tag>></$list>
<<tag-picker tagField:"exclude">>
<$list filter="[enlist{!!include}tagging[]] -[enlist{!!exclude}tagging[]] +[sort[]]"><$link/><br/></$list>
Thank you Roland, it does as I asked.
Peter
Thank you Eric, it works well.
Thank you this does what I asked and much more!