If we use the tag macro to display tag pills in a list widget, and we get the same tags several times, the popup menu will open for all identical tags. We can prevent this by using a let widget and overriding the value of the transclusion variable, which is used by the qualify macro to generate the unique identifier of the popup.
But we dont even need to use a let widget, we can use the counter attribute instead (edit: use the variable attribute for best performances) ! Each run of the list widget is unique, and thus we will get a unique value for the qualify macro, and therefore, unique popup menus.
Thanks for sharing this useful code pattern, new features like the counter need exposure as solving other issues.
@telumire can you explain why setting the transclusion variable works for the tag macro and why you want the same tag pill to display 6 times?
One additional trick to add to this is to use the counter = 1 to trigger a heading. Perhaps not as applicable in this above example; as a rule I call the counter variable “item” and if I have its total “items”.
eg; Heading Inside a list using counter=item
<$list filter="filter" counter=item>
<$list filter="[<item>match[1]]" variable=~>Heading if 1 or more items satisfy filter</$list>
<!-- Each item below -->
</$list>
In the above the heading will only appear if there is one or more items
If before hand you count the total number of items you can also test for the last item to add a footer to the list.
<$set name=items filter="filter count[]]">
<$list filter="filter" counter=item>
<$list filter="[<item>match[1]]" variable=~>Heading if 1 or more items satisfy filter</$list>
<!-- Each item below -->
<!-- footer below -->
<$list filter="[<item>match<items>]" variable=~>Footer after all items, if 1 or more items satisfy filter</$list>
</$list>
Observe the plural of item is items (ie total number of items)
That’s an excellent trick, and should work well for a number of common usecases.
For those who don’t know, the heart of this trick is the “transclusion” variable. The core automatically assigns it within transclusions, giving it a value made up of the name of the target tiddler/field/index combined with the “currentTiddler” variable.
The “transclusion” variable is then used by the <<qualify>> macro in a subtle way: the magic numbers in the result of the macro are a hash of the concatenation of all the values of the transclusion variable assigned going back through all the ancestors of the current node.
That’s why the solution to not having unique values returned by the <<qualify>> macro is generally either to introduce a transclusion or an assignment to the “currentTiddler” variable.
The trick here is that using it as a list counter is a convenient shorthand for directly assigning a unique value to the “transclusion” variable for each list item.
There’s a marginally easier way to accomplish this. As the docs notes, the name of the counter variable with -first or -last appended is set to yes or no as appropriate. So your example can be accomplished with:
<$list filter="filter" counter="item">
<$list filter="[<item-first>match[yes]]" variable="ignore">
Heading if 1 or more items satisfy filter
</$list>
<!-- Each item below -->
</$list>
It’s more of a help when one is trying to detect the last item; the alternative requires the number of items to be precomputed.
“Using the counter in lists can reduce performance when working with list items that dynamically reorder or update themselves”
We really should not discourage people from using list counters. For the situations where a counter is required, it will always be more efficient to use the built-in counter rather than trying to work around it in other ways. So the best advice we should give is much simpler: don’t use the counter attribute unless you really, really must. If you can’t see an easy alternative then there probably isn’t one, so just go ahead and use it.
Yes I think it should work, and that should probably be the recommended approach in most situations.
It’s also worth noting that using the template attribute already has the same effect because it transcludes the template tiddler for each item in the list.
If you look into $:/core/ui/TagTemplate, you’ll see that it uses the qualify macro, and the qualify macro use the transclusion variable (see @jeremyruston’s excellent explanation).
That is true, but it would require a separate tiddler (which is fine; but I like self-contained solutions ).
Another way to achieve that is to use a let (or set, vars..) widget, would that be better for performances?
No. … I think using the transclusion variable will be the approach to go for the usecase mentioned in the OP. The list-widget basically does the same thing as the let-widget in your example.
I just want to share that most of the times I use the list widget I make it operate on the current tiddler variable so then when I use the tag template or <<tag tagname>>it is qualified to the current tiddler and the qualification works well.