Why $let only outputs first item?

I know it is by design, but I repeatedly trip on in; Please expain (so I can understand and internalize it) what the reason is for $let only outputting the first result and not the full filter result like for $set here:

<$let nrs={{{ one two }}} ><<nrs>></$let>
→ one

<$set name=nrs filter="one two" ><<nrs>></$set>
→ one two

Thank you.

The “first result only” handling applies to all uses of “filtered transclusion” when used as the value of a widget parameter… for ANY widget, not just the $let widget.

I suppose it could have been implemented to return multiple results (space-separated with doubled square brackets around any result that contains spaces), and then if you only wanted the first result you could add +[first[]] to the end of the filtered transclusion syntax.

Conversely, using the current “first result only” handling, if you DO want to use the "full filter result like for $set", you can add +[format:titlelist[]join[ ]] to the end of the filtered transclusion syntax, which would then give the same result as you get with the <$set name="..." filter="..." /> syntax.

Note that the format:titlelist[] filter operator was only added some time after the filtered transclusion parameter syntax… in part to address this very issue.

One possible explanation for this design choice was perhaps it was thought that parameters that expect a single value are the significantly more common use-case, so it was “cleaner” to return just the first result, rather than always having to remember to add +[first[]] all the time.

-e

1 Like

@EricShulman - appreciated!

Aha!

Oho!

Hi @twMat your example is more instructive if you use example data that includes spaces:


<$let nrs={{{ [[one two]] [[three four]] }}} ><$text text=<<nrs>>/></$let>
→ one two

<$set name=nrs filter="[[one two]] [[three four]]" ><$text text=<<nrs>>/></$set>
→ [[one two]] [[three four]]

You can see that the problem is that if we return the filter results as a stringified list then we have to wrap items containing spaces in double square brackets.

Is perhaps this even clearer (avoiding the textwidgets)?

<$let nrs={{{ [[one one]] [[two two]] }}} ><<nrs>></$let>
→ one one

<$set name=nrs filter="[[one one]] [[two two]]" ><<nrs>></$set>
→ [[one one]] [[two two]]

verbally expressed as:

“filtered transclusion in a widget” → “the first item stringified”

BTW, does the following fully cover the reasoning behind this?

…plus…

the output is stringified so to not having to deal with brackets.

Does that cover the reasoning for the design choice?

Also note that if any of the data returned by filters is already wrapped in braces, i.e. the braces are a part of the data, there is no reliable way to return multiple items as a stringified list short of returning a blob of JSON.

More like: “filtered transclusions as a parameter” - It’s the same for eg: DIV or any other HTML element.

\define classA() aaa
\define classB() bbb

<!-- this will use class="aaa" -->
<div class={{{ [<classA>] [<classB>] }}}>test A</div>

<!-- this will use class="aaa bbb" -->
<div class={{{ [<classA>] [<classB>] +[join[ ]] }}}>test AB</div>
1 Like

Thanks @pmario

In this, where do the quotes in class="aaa bbb" come from?

<!-- this will use class="aaa bbb" -->
<div class={{{ [<classA>] [<classB>] +[join[ ]] }}}>test AB</div>


And related (albeit deviating from the OP now):

<input type=checkbox id=<<id>> >
<style>[id="<<id>>"]{ ... }</style>

Here id has the value foo bar. The above is correct syntax according to the inspector tool, but why must quotes not be used for the first call, but quotes must be used the second? Again, the strange thing is why the first id=<<id>> automatically becomes id="foo bar" i.e with quotes.

IDs must not contain whitespace. See: id - HTML: HyperText Markup Language | MDN, so technically the second style id should also work without the quotes.

In TW for best practice we use double-quotes for every HTML and widget parameters, because some parameters like class and many widget parameters allow “text with spaces”. Since most users copy / paste code from the TW core it makes sense to include those quotes, even if they are not needed for our examples. So if users start to use “parameters with spaces” our examples do not break.

The TW parser knows, that HTML and widget attributes need to deal with whitespace, so they add double quotes by default.

Quotes are necessary. According to the spec classes have to be “space separated”. See: class - HTML: HyperText Markup Language | MDN and HTML Standard

Since the HTML parser needs to know where class-definitions start and end we need double quotes. eg:
<div class="tc-a tc-b" title="hello"> If the quotes would be missing <div class=tc-a tc-b title="hello"> it would create this HTML code <div class="tc-a" tc-b="true" title="hello"></div> which is not what we want.

This may not be a good way to see/explain it, but I find this helps me keep things straight in my head.

In your $let, you are assigning a list to the variable. A variable is like an “input” text widget (I.e. one line): it expects a one-liner value. A list (the results of a filter) is like a “textarea” text widget (I.e. multi-line).

Well, if we try to feed a multi-line thing into a one-line thing, only the first line of the multi-line thing is going to go into the one-line thing.

Ugh, that is wordy for what seems like a simple true/false thing in my head…

1 Like