Search Operator

Hello again!

I’m trying to show a button only if a field named <BasisListe> does not contain the word <Items>.

My idea is something like

<%if [!search:<BasisListe>:words<Items>] %>
   show the button
<%endif %>

I think the main problem is, that it doesn’t look in the Field named with the value of <BasisListe>.

Another approach was to start with

<%if [<currentTiddler>get<BasisListe>...] %>
   show the button
<%endif %>

but I still failed.

Thanks for your help,
Ben

I’m not sure what level of background understanding you have, but it looks like you’re using angle-brackets <like this> when you want to reference regular strings.

(Unless you’ve defined variables named BasisListe and Items and you’re zooming into the <% if … %> conditional syntax within the scope of those variables…)

If you’re actually looking for the word “Items” in a field named BasisListe then you want something like:

<%if [{!!BasisListe}split[ ]match[Items]] %>

… but you say you want the button only if that word does not appear in such a field, so one intuitive way is:

<%if [{!!BasisListe}split[ ]match[Items]] %>
<% else %>
button here
<% endif %>

Ah this makes me think what you want is something more like:


<$let Items={{!!items}}>

<% if [<currentTiddler>has{!!BasisListe}get{!!BasisListe}split[ ]match<Items>] %>

<<condition>>

<% else %>

@@ button here @@

<%endif %>

</$let>

That should retrieve a fieldname from the field called BasisListe (and the {!!curlybracketfieldname} shows that we’re reaching THROUGH that field, transcluding its value)… and look for the <Items> (however that variable has been defined — I just made it look at field {{!!items}} here) … within that field. Show the button only if nothing results from this field check.

The variable <<condition>> offers a really useful troubleshooting step. Delete it once you don’t need it, but in the meantime, it shows what the <% if %> widget’s filter has come up with.

[Edit to add: Working demo if you want to tinker with this approach. ]

2 Likes

split[ ]match<Items> is a good option if you want to find only exact word matches (and if <<Items>> does not itself contain spaces, of course!) But if you want to preserve the “fuzziness” of search (e.g. case-insensitivity or word-internal matches), you can do that too. Here’s an adaptation of @Springer’s conditional code:

<$let
	Items={{!!items}}
>
<% if [{!!BasisListe}!search:title<Items>] %>
	@@ button here @@
<% endif %>
</$let>

This assumes that BasisListe is the literal name of the field, rather than a variable <<BasisListe>> containing a different field name. If you did in fact intend <<BasisListe>> to refer to a variable defined outside the conditional, you could replace {!!BasisListe} with <currentTiddler>get<BasisListe>.

In either case, the real trick here is the use of search:title, and the key point is that TW filters use :title (and sometimes {!!title} and <currentTiddler>) to refer to the input value, whatever that is. So we can use search:title to search inside each string supplied to the search operator — regardless of whether it corresponds to an actual tiddler title.

Here are some more simple examples illustrating this principle:

{{{ [[A tiddler that does not exist!]search:title[a]] }}} = A tiddler that does not exist!

{{{ [enlist[A B C D E]search:title[a]] }}} = A

And we can use !search:title in the same way:

{{{ [enlist[A B C D E]!search:title[a]] }}} => B C D E

This lets us incorporate the negation directly into the conditional filter, so we don’t need the <% else %> case: the button can go directly after <% if ... %>.

2 Likes

You can use dynamic suffixes, but as far as I know, only with a bit of indirection:

<$let fltr=`[!search:$(BasisListe)$:word[$(Items)$]]`>

<%if [<currentTiddler>filter<fltr>] %> 
  Doesn't match!
<% else %>
  Matches!
<%endif %>

</$let>

Here we define a variable fltr which embeds your actual search criteria (including the leading !) and then we use it by passing it to the filter Operator in your actual filter.

You can test this by downloading the following and dragging the resulting file onto any wiki: Dynamic suffix.json (914 Bytes)

1 Like

Thanks for your help!

After some testing the best solution seems to be

<%if [<currentTiddler>get<BasisListe>split[ ]match<Items>] %>
<%else %>
   show the button
<%endif %>
2 Likes

I am surprised no one mentioned the contains Operator because I find it is limited in its use but really is only useful in this specific case;

[all[current]!contains:BasisListe<Items>]
  • Not tested just now

If the fieldname is truly variable then you may need to resort to @Scott_Sauyet’s indirection above.

  • Although I expect we can find another method,
  • The %if though demands a " raw filter" we could use a list widget for the same;
<$list filter=`[all[current]!contains:$(BasisListe)$<Items>]` variable=nul>

When `<<BasisListe>>` not contains `<<items>>`

</$list>

Again not tested

  • You could also use emptyMessage for the opposite

However this does suggest the contains operator could have a second parameter that would set the fieldname to use as with any suffix where we may want to set programmatically/via a variable.

  • however there are other approaches to use a variable to specify a fieldname.

Providing a exhaustive list of alternative examples would be just that, exhausting :nerd_face: .

<$list filter=`[all[current]!contains:$(BasisListe)$<Items>]` variable=nul>

When `<<BasisListe>>` not contains `<<items>>`

</$list>

I’ve tried this approach as well and it also works using the shortest code.

$(BasisListe)$ is something I’ve seen before but I didn’t understand what it is doing. Now I get it…

To word it correctly, in the above example and only within backticks, $(BasisListe)$ is “substituted” with the value in the variable BasisListe, in this case we are using substitution so as to use this value in a :suffix of the contains operator. The parameters of the contains operator, allows us to give it a variable name <items> so we do not need to do the substitution for it.

  • You could use a
    • [literal], {!!fieldname}, {tiddlername} or {tiddlername!!fieldname}, or {tiddlername##indexname} as well.

Because the result of the backticks above constructs a valid filter string, when set as the “attribute value” of a filter= parameter, it uses the resulting filter (with substitutions) in the $list widget, and at that point, standard filter processing will provide the value of the items variable as the first parameter, to the contains operator.

In summary if we want to use a variable to provide a value to an operator (in the suffix, not a parameter) we need to construct the filter first, using substitution and only then use the result as a filter.

[Note] I have long felt we should study and document the creation of “filter strings” for use as filters, but perhaps if we had a way to use variable in the suffix of an operator it would be even better.