Filter to list tiddlers matching user-input field values

Hello. I want to create a UI to list all tiddlers filtered by user-input field values. This is simple demo:

This is okay if I have filled all user-input data. However, if leave subject blank then nothing is shown. (In my wiki, all Source tiddlers with meduim=textbook have non-empty subject field). This is to be expected since, according to the doc (https://tiddlywiki.com/#field%20Operator) when the field value is empty, it lists tiddlers that don’t have that field (or with empty value).

However, my expected behavior is that if I leave some field blank, then it means I don’t want to filter by that field. (For example, if subject input is empty then it should list all tiddlers regardless of the subject field.) How do I achieve this in a single filter expression*? Any help is appreciated.

*The filter will be used in a dynamic table, so I need “one filter for all”.

Hi,

Also Its nice if you include your code in the post not just an image, because its easy to copy and edit in response.

Here is the logic, but not in a single filter.

<$list filter="[{$:/temp/testfilter##subject}!is[blank]]">
   <list-links "[tag[source]medium<medium>subject<subject>]">>
</$list>
<$list filter="[{$:/temp/testfilter##subject}is[blank]]">
   <list-links "[tag[source]medium<medium>]">>
</$list>

So lets combine them
[{$:/temp/testfilter##subject}!is[blank]tag[source]medium<medium>subject<subject>] [{$:/temp/testfilter##subject}is[blank]tag[source]medium<medium>]"

I have not tested this. But if the same tiddler is found twice it will be deduplicated.

Hi. Sorry I did not include the code. Here it is:

<$vars medium={{$:/temp/testfilter##medium}} subject={{$:/temp/testfilter##subject}}>
<<list-links "[tag[Source]medium<medium>subject<subject>]">>
</$vars>
<$list filter="[{$:/temp/testfilter##subject}!is[blank]]">
   <list-links "[tag[source]medium<medium>subject<subject>]">>
</$list>
<$list filter="[{$:/temp/testfilter##subject}is[blank]]">
   <list-links "[tag[source]medium<medium>]">>
</$list>

Thanks. This was my solution as well. But there will be many fields for Source tiddlers so the code might get complicated.

So lets combine them
[{$:/temp/testfilter##subject}!is[blank]tag[source]medium<medium>subject<subject>] [{$:/temp/testfilter##subject}is[blank]tag[source]medium<medium>]"

This returns empty. The part [{$:/temp/testfilter##subject}!is[blank]... would return user-input (algebra in the picture) which is not the name of a tiddler so it doesn’t pass tag[Source].

I think the logic needs to be reversed somehow. Select the list of possible tiddlers then see if the fields match

1 Like

@Pak I don’t have the opportunity at present to think about your data structure carefully and a specific solution but here are some thoughts that might help.

The filter operator and :filter and :map filter run prefixes should be useful here.

Here is some untested code to give you an idea as to the direction I am thinking, can probably be improved upon:

\define subject-filter() [{$:/temp/test##subject}!is[blank]match{!!subject}] :else[{$:/temp/test##subject}is[blank]then[keep-me]]

\define medium-filter() [{$:/temp/test##medium}!is[blank]match{!!medium}] :else[{$:/temp/test##medium}is[blank]then[keep-me]]

{{{ [tag[Source]filter<medium-filter>filter<subject-filter>] }}}

The key thing to understand about filter and :filter is that it doesn’t matter what they return, they just need to return a non-empty result for the input titles you want to keep.

The above can probably be simplified along these lines:

\define get-filter(source) [{$:/temp/test##$source$}!is[blank]match{!!$source$}] :else[{$:/temp/test##$source$}is[blank]then[keep-me]]

{{{ [tag[Source]filter<get-filter medium>filter<get-filter subject>] }}}
3 Likes

@saqimtiaz Wow! this works like a charm! Exactly what I want it to be. Thank you!

I never fully understood about this filter and :filter prefix thing. Like what is the difference between

[{$:/temp/test##subject}!is[blank]match{!!subject}] :else[{$:/temp/test##subject}is[blank]then[keep-me]]

and

[{$:/temp/test##subject}!is[blank]match{!!subject}else[{$:/temp/test##subject}is[blank]then[keep-me]]

Why can’t we concatenate the else? The latter “works” (as in does not give filter error) but it does not seem to do anything regardless of what I put for subject

Unfortunately I don’t have the opportunity to delve into an explanation of the difference between an operator and a prefix for a filter run.

Understanding the difference between a filter expression and filter runs, and how the prefixes change the behaviour of filter runs would be a good start. Here is the documentation for it:

https://tiddlywiki.com/#Filter%20Expression:[[Filter%20Expression]]%20[[Filter%20Run]]

Edit: Also have a look at the else[] operator documentation, and note how it accepts a single operand and not a filter expression.

1 Like

Thank you for the link. I will try to study those :slight_smile:

This would have made a lot more sense (to me, at least) if the tiddler were named $:/test/algebraTextbook, So, in order for me to make sense of the example. I’ll start by making that correction. and, really, Thanks.

~ @applemcg a/o @shell_functions