Problem with style associated with labels in view template

Hello everyone.

I’m continuing with the programming and I’m stuck again. I think I’m close, but there’s something I’m missing. I’m trying to get the tiddlers that have the “solution” and “Review” labels to display in a certain way. If they don’t have the latter label, they display differently in the view template I created.
I’m using this code, but it doesn’t work:

<$list filter="[all[current]tag[solucion]]">
<$set name="bordeColor" value={{{ [all[current]tag[Revisar]then[rojo]else[negro]] }}}>
<$set name="claseCompleta" value={{{soluciones-cabecera <<bordeColor>>}}}>
<div class=<<claseCompleta>>>
...
</$set>
</$set>
</$list>

Previously, I used this other code, but it didn’t work either:

<$list filter="[all[current]tag[solucion]]">
<$set name="bordeColor" value={{{ [all[current]tag[Revisar]then[-rojo]else[-negro]] }}} />
    <div class="soluciones-cabecera<<bordeColor>>">
...
</$set>
</$list>

The associated CSS code is this:

.soluciones-cabecera.rojo{
  padding: 0.75rem 1.25rem;
  margin-bottom: 1rem;
  border-radius: 0.25rem;
  background-color: #f0f0f0;
  border: 4px solid red;
}
.soluciones-cabecera.negro{
  padding: 0.75rem 1.25rem;
  margin-bottom: 1rem;
  border-radius: 0.25rem;
  background-color: #f0f0f0;
  border: 4px solid black;
}

If I directly add the class I want to apply to the tiddler, it displays correctly, but with the code that does what I want, I can’t find the way. What am I forgetting?

Thank you very much.

In TW syntax, quote marks (" " or ' ' or even """ """) around a value mean that it will be treated literally — that is, without evaluating any variables or other wikitext inside the quotes. That’s why your first attempt class="soluciones-cabecera <<bordeColor>>" didn’t work: <<bordeColor>> is treated as a literal value, referring to a (non-existent) .<<bordeColor>> class.

So how do we fix this?

Option 1: The easiest way to combine a static value (soluciones-cabecera) and a variable (<<bordeColor>>) in the same attribute (here, the value of the CSS class) is by using substituted attribute values. Here’s a simple version:

<$list filter="[all[current]tag[solucion]]">
<$let bordeColor={{{ [all[current]tag[Revisar]then[rojo]else[negro]] }}}>
	<div class=`soluciones-cabecera $(bordeColor)$`>
		...
	</div>
</$let>
</$list>
  • Note the backticks rather than quote marks around the value of class! These signify that the variable $(bordeColor)$ should be replaced with its value before the class is applied.
  • I also replaced the $set widgets with $let, which is a shorter way to set a variable’s value.

Option 2: But we can actually get even simpler than this! If you look at the documentation for substituted attribute values, you’ll notice that you can use either a $(varname)$ or a ${ filter expression }$. If you use the filter syntax, it will be fully evaluated and the first result will be used in your attribute. This means that we can skip the <<bordeColor>> definition entirely and do this:

<$list filter="[all[current]tag[solucion]]">
	<div class=`soluciones-cabecera ${ [all[current]tag[Revisar]then[rojo]else[negro]] }$`>
		...
	</div>
</$list>

And just for fun…

Option 3: The backtick substitution syntax was only introduced in 5.3.0… so how would we solve this problem in an older wiki? Here’s an “old-fashioned” way to do it, using a filtered transclusion {{{ filter }}} to build the class in place:

<$list filter="[all[current]tag[solucion]]">
	<div class={{{ soluciones-cabecera [all[current]tag[Revisar]then[rojo]else[negro]] +[join[ ]] }}}>
		...
	</div>
</$list>

Here, the important thing to notice is the use of +[join[ ]]. A filtered attribute value evaluates the filter and then uses only its first result as the value of the attribute. So if we used class={{{ soluciones-cabecera [all[current]tag[Revisar]then[rojo]else[negro]] }}} without join, we’d just get class="soluciones-cabecera". +[join[ ]] solves this issue by merging all the results of all the filter runs into a single string with a space between each result, and that gives us class="soluciones-cabecera rojo" or class="soluciones-cabecera negro".

Personally, I’d generally use solution #2, but you should pick whichever makes most sense to you. Have fun and let me know if you have further questions.

4 Likes

Hi Emily.

I’m away from home, but I ran a test on my phone and it works as I wanted.
I appreciate you taking the time to break down the various ways to solve this problem; it helps me a lot.
But I have a question. Why is the second code model failing?

<$set name="claseCompleta" value={{{soluciones-cabecera <<bordeColor>>}}}>
<div class=<<claseCompleta>>>

Isn’t it the same as the first, or is it?

Thank you.

Two issues here:

  1. The contents of {{{ }}} are a filter, so they need to follow filter syntax. You’d need to write {{{ soluciones-cabecera [<bordeColor>] }}} for the variable <<bordeColor>> to be properly evaluated; otherwise, it will be treated as a literal single-word value, just like soluciones-cabecera, and we would run into this problem again…

Except

  1. Remember what I said about filtered attribute values?
  • If you used value={{{ soluciones-cabecera [<bordeColor>] }}}, it would first evaluate the variable to value={{{ soluciones-cabecera rojo }}} or value={{{ soluciones-cabecera negro }}}.
  • However, inside a filter, each result is treated separately — they’re not automatically combined. So “soluciones-cabecera” and “rojo” are two separate values, and only the first (“soluciones-cabecera”) will be used as the value of the value attribute.
  • To solve this, we need to add +[join[ ]] as I did in Option #3 above:
value={{{ soluciones-cabecera [<bordeColor>] +[join[ ]] }}}

And this would give you the correct value for <<claseCompleta>>. :slightly_smiling_face:

The reason I recommended using the backtick syntax instead of {{{ }}} is because, unlike filtered transclusions, it does treat spaces as literal values to be preserved. This lets us write

value=`soluciones-cabecera $(bordeColor)$`

without the need for +[join[ ]]: the variable $(bordeColor)$ gets replaced with the proper value, but the rest of the string (including white-space) is left as-is.

2 Likes

Hi Emily.
I’ve come to the same conclusion as you; it’s clear to me now. I’ve also tested the code this way, and it also works (although for some reason another part of the code is broken; I must have accidentally deleted or changed something… :sweat_smile:):

<$list filter="[all[current]tag[solucion]]">
<$set name="bordeColor" value={{{ [all[current]tag[Revisar]then[rojo]else[negro]] }}}>
<$set name="claseCompleta" value=`soluciones-cabecera $(bordeColor)$`>
<div class=<<claseCompleta>>>

Thank you very much.

1 Like

I’m glad you got it working! If you want to define bordeColor and claseCompleta separately, you could simply your code a little by putting them in the same $let widget:

<$list filter="[all[current]tag[solucion]]">
<$let 
	bordeColor={{{ [all[current]tag[Revisar]then[rojo]else[negro]] }}}
	claseCompleta=`soluciones-cabecera $(bordeColor)$`
>
<div class=<<claseCompleta>>>

One advantage of $let over $set is that it lets you define multiple variables in the same widget, and a variable’s definition can include any variable that has been previously defined — so it’s a little more compact. Functionally, though, they do the same thing, so by all means stick with $set if it’s most comfortable for you.

Very useful, @etardiff! This is one of those occasions when I realize I must not have had the bandwidth to absorb something the first time around — $(value)$ syntax must have felt like enough of a learning curve. But now I can go back and check out the filter version. Thanks for explaining so clearly!

1 Like

Just to follow up: here’s a demo of on-the-fly filter expression as variable within a style declaration practicing putting the `${ … }$` syntax to use. The demo allows easy live edits to tinker with how a complex filter expression can work within a style declaration — no <$set> or <$let> involved!

3 Likes

This is worthy of inclusion in the documentation both for “Filtered Transclusions” and the “backtick syntax”.

1 Like

No prizes for guessing who gets this week’s prize for the “Missing manual entry of the week” award:

:trophy:
:heart:

4 Likes

Perhaps this link should be emphasised Attribute Values - literals and given an honorable mention here Formatting in WikiText

Hi Emily.

Yes, what you’re saying about $let was told to me yesterday by Google AI, which, by the way, explains code much better than ChatGPT, at least in the case I was working on.
But in the end, it came close but wasn’t able to give me working code, mainly because it didn’t know or didn’t think to implement backtick substitution or the fact that in TW syntax, quote marks (" " or ’ ’ or even “”" “”) around a value mean that it will be treated literally.
I’ll explain it with your example. :wink:

Have a nice day.

Thank you all so much for this. It’s a privilege to be able to participate in a forum like this with people like you, and to continue learning a little more programming and tricks every day to implement in our beloved Tiddlywiki.

I wish you all the best.

1 Like

This is not only well documented here Attribute Values - literals but it is importiant to acknowledge that dozens if not hundreds of programing and macro languages adhear to this same set of rules.

I know tiddlywiki may seem to be an “odd one” sometimes but in fact with HTML and Javascript and wise choices by @jeremyruston et all most of tiddlywiki does map to global standards a lot of the time.

  • This means often when you learn something in tiddlywiki it is applicable in a lot more places than you first think.
  • This also justifies a “life long learning process” with tiddlywiki, as it is not as bespoke as you may think.
  • Having come from a programing perspective (long time ago) this is quite obviouse and non programers do need to trust programers when we say “TiddlyWiki is not unnessasarily complex, but it can do complex things”.

Hi Tones.

Thanks for your kind words.

I understand that the “” may be obvious to people with programming knowledge, but if you don’t have a programming background, it’s not so obvious.

I know it’s a long learning curve with Tiddlywiki to get it the way I like it. And in part, it’s because I want to do things myself and learn, since there are plugins that could do some of the things I’m looking for. I try to figure out how they work, and then I only use what I need. Obviously, there are things that I see as beyond my reach, and I don’t try them anymore.

You’re right about the Tiddlywiki documentation. After the tip etardiff gave me, I took a look and it was clear. But as you say, Tiddlywiki takes time; there’s quite a bit of documentation, and the rest of the things you have to do don’t leave you enough time to dedicate to it.

Sometimes I learn something, and then, due to life itself, I go months without looking at anything about Tiddlywiki, and when I come back, I don’t know where to start. That’s when you go back to the forum to see if anyone else has asked the same question and found the answer, or if not, you ask the community, which is one of the best things about this wonderful program.

Have a nice day.

1 Like