Could we have a fusion between the list widget with conditional syntax?

I like the options the conditional shortcut syntax offers in an elegant way, but in many cases, I would the <currentTiddler> variable within. This is why I often end up stacking lists in emptyMessages. Could we have the best of both worlds in one widget?

I also would like to have something for the scenario where the results of a first list should excluded from the second list.
Like

  1. searchresults where string is in title, alias
  2. searchresults where string is in caption - results of 1
  3. searchresults where string is in tags -(1+2)
  4. searchresults where string is in text -(1+2+3)

I am not sure I follow but;

I know we have customarily also used the list widget for conditional branching. If in this case it often has one or no, or one of two outcomes (thus emptyMessage). With the advent of %if else we can have more complex structured and optimal decision trees however lets not forget the $list widgets core functionality which is to generate a list to process iteratively (or recursivly).

Of course all of this gets more complex when some fairly advanced and cumulative logic in filters and functions including filters/functions that are themselves conditional, recursive and/or iterative.

For this reason now I tend to separate the list function from the conditional function when using List, and use %if else when it is mostly conditional. In many cases nesting if and listing in each other or both depending on the problem.

The documentation for Conditional Shortcut Syntax says:

Within an “if” or “elseif” clause, the variable condition contains the value of the first result of evaluating the filter condition.

Thus, within a particular “if” or “elseif” clause, you can set <<currentTiddler>> by writing:

<$tiddler tiddler=<<condition>>>
...
</$tiddler>

or, if you prefer:

<$let currentTiddler=<<condition>>>
...
</$let>

-e

1 Like

Thank you @EricShulman, I overread this!
This is already very helpful and would be worth also an example in the documentation. The TLDR; way is to look right there - I am afraid.

But my searchresult-riddle is still unsolved.
My solution is not great yet and adding more options gets really tedious if you want a short resultlist where the same tiddler does not appear 4 times…

<$list filter="[!is[system]search:title{$(searchTiddler)$}sort[title]limit[1]]" >
//<small>im Titel: <br></small>//</$list>
<$list filter="[!is[system]search:title{$(searchTiddler)$}sort[title]limit[250]]" template="$:/plugins/JJ/multimenu/AliasTemplate"/>
<$list filter="[!is[system]search:alias{$(searchTiddler)$}sort[title]limit[1]]-[!is[system]search:title{$(searchTiddler)$}sort[title]]">//<small>Alias-Titel</small>//</$list><$list filter="[!is[system]search:alias{$(searchTiddler)$}sort[title]limit[250]]-[!is[system]search:title{$(searchTiddler)$}sort[title]limit[250]]"template="$:/plugins/JJ/multimenu/AliasTemplate"/>
<$list filter="[!is[system]search{$(searchTiddler)$}sort[title]limit[1]]-[!is[system]search:alias{$(searchTiddler)$}sort[title]limit[1]]-[!is[system]search:title{$(searchTiddler)$}sort[title]limit[1]]">
//<small>im Text:</small>//
</$list>
<$list filter="[!is[system]search{$(searchTiddler)$}sort[title]limit[250]]-[!is[system]search:alias{$(searchTiddler)$}sort[title]limit[250]]-[!is[system]search:title{$(searchTiddler)$}sort[title]limit[250]]" template="$:/plugins/JJ/multimenu/AliasTemplate"/>
...

Perhaps you could use one list filter to search all :* fields, then within that test for the different conditions with a set of independent if/else statements.

Personally I like to pull out parts of filter and build function to replace them, this makes each filter more readable.

  • The more you can see and read in a single view the easier it can be to debug.
  • I see the same piece of filter being used a number of times, these are great for functions, even if you negate them later eg the - or except:

I don’t have time to rewrite this just now, maybe later if you have not resolved this.

1 Like

Would something like this work for you?

\function title.list() [format:titlelist[]join[ ]]

\procedure results-list(template:"$:/plugins/JJ/multimenu/AliasTemplate")
<$list filter="[enlist<condition>sort[title]limit[250]]" template=<<template>> />
\end

<$let
	searchText={{{ [<searchTiddler>get[text]] }}}
>
<% if [!is[system]search:title<searchText>] +[title.list[]] %>
	//<small>im Titel: <br></small>//
	<<results-list>>
<% endif %>
<% if [!is[system]search:alias<searchText>] -[!is[system]search:title<searchText>] +[title.list[]] %>
	//<small>Alias-Titel</small>//
	<<results-list>>
<% endif %>
<% if [!is[system]search:text<searchText>] -[!is[system]search:alias<searchText>] -[!is[system]search:title<searchText>] +[title.list[]] %>
	//<small>im Text:</small>//
	<<results-list>>
<% endif %>

</$let>

Here, I’m taking advantage of the <<condition>> variable Eric mentioned. A standard <% if ... %> statement will save only the first result of the filter as the value of <<condition>> (behind the scenes, it automatically adds limit[1].) But if we use format:titlelist[]join[ ] to save the entire list of results as a single string in title-list format, we can then use enlist<condition> inside the conditional to retrieve the full contents of the list.

Here’s what that looks like without the function/procedure I added for brevity above:

<% if [!is[system]search:title<searchText>] +[format:titlelist[]join[ ]] %>
	//<small>im Titel: <br></small>//
	<$list filter="[enlist<condition>sort[title]limit[250]]" template="$:/plugins/JJ/multimenu/AliasTemplate" />
<% endif %>

To cut down on repeated content, I defined a custom function title.list…

\function title.list() [format:titlelist[]join[ ]]

And a custom procedure that wraps the inner $list:

\procedure results-list(template:"$:/plugins/JJ/multimenu/AliasTemplate")
<$list filter="[enlist<condition>sort[title]limit[250]]" template=<<template>> />
\end

You seemed to be using $:/plugins/JJ/multimenu/AliasTemplate as the list template in all cases, so I made it the default value of the template parameter. But if you want to use a different template for a particular list, you can simply declare it as part of the procedure-call, e.g.

<<results-list MyAlternateTemplate>>

You’ll also notice I moved the sort and limit steps out of the outer filter (which determines whether anything should be displayed) and into the inner filter used in <<results-list>>. Sorting can be time-consuming, so it’s generally best to do it at the last possible moment — i.e., when the content is actually being rendered.

As you can see, my suggested code above does still include some recalculation of previously-used filters, as in [!is[system]search:text<searchText>] -[!is[system]search:alias<searchText>] -[!is[system]search:title<searchText>]. If you wanted to further improve your search efficiency, you could save each step as a precalculated title list in a variable…

\function title.list() [format:titlelist[]join[ ]]

\procedure results-list(template:"$:/plugins/JJ/multimenu/AliasTemplate")
<$list filter="[enlist<condition>sort[title]limit[250]]" template=<<template>> />
\end

<$let
	searchText={{{ [<searchTiddler>get[text]] }}}
	titleResults={{{ [!is[system]search:title<searchText>] +[title.list[]] }}}
	aliasResults={{{ [!is[system]search:alias<searchText>] -[enlist<titleResults>] +[title.list[]] }}}
	textResults={{{ [!is[system]search:text<searchText>] -[enlist<aliasResults>] -[enlist<titleResults>] +[title.list[]] }}}
>
<% if [<titleResults>!match[]] %>
	//<small>im Titel: <br></small>//
	<<results-list>>
<% endif %>
<% if [<aliasResults>!match[]] %>
	//<small>Alias-Titel</small>//
	<<results-list>>
<% endif %>
<% if [<textResults>!match[]] %>
	//<small>im Text:</small>//
	<<results-list>>
<% endif %>

</$let>

This will likely be somewhat faster in a large wiki, since you’re reducing the number of times you have to search all your non-system tiddlers. Whether it feels visually simpler or not is probably a matter of user preference.

As a side note, I did a lot of copy-pasting while writing this… hopefully it didn’t introduce any errors, but if you find one, please let me know. :slightly_smiling_face:

3 Likes

Are these filters slow? IMO you should store some of the resulting list in variables and use them later for more refinement, to speed things up.

MultiValueVariables should come in handy here.

1 Like