Disclaimer: I fully accept responsibility, I acknowledge this is a PEBCAK issue, despite me not being a native English speaker. My [hopefully] relatively impartial comparison rule is, as I wrote above, that this is pretty much the only piece of documentation about filter operators that gave me trouble. So far I don’t have any advices how to improve this particular situation here (since I don’t even understand this operator yet!). Perhaps other TiddlyWiki users remember their aha moment (after not getting it after the first read) about it and could share what made it click for them.
Thank you for taking this on; this has been long needed!
But I’m not sure if this is capturing the right thing here. I can’t see the actual use of the function operator here, just of functions. (Never mind, I was blind!)
Sure, but it’s not about each. I’ll try to look at each soon, but if it’s what I expect it to be (from my JS experience), then it’s a function I mostly avoid anyway.
Scott will have to weigh in with the JS comparison, but here’s my layperson’s understanding:
each[field] returns each input tiddler (i.e., each tiddler produced by the preceding filter steps, or each tiddler in the set of all[tiddlers] if each is the first filter step) with a unique value of the field field.
IMO, this is the most confusing use. From the name alone, I would expect each to return each unique value of field, but this is not what it does; instead, it returns each tiddler that has a unique value. When multiple tiddlers have the same field value, it returns only the first title with that value.
each treats field values as literal strings, not title lists: field: A B C and field: C B A are unique field values, even though they contain the same list-items.
If you want the field values, not the titles of the tiddlers that have them, you need each[field]get[field].
By contrast, each:list-item[field]does return field values (not tiddler titles), with a twist: each field value is treated as a title list, and list items that appear in more than one tiddler’s field only appear once in the output of each:list-item.
As you can see above, each:list-item[field] is equivalent to get[field]enlist-input[]unique[]
I’ve never actually used each:value[], but at a glance it seems to be equivalent to unique[].
Unlike the other two each variants, this one isn’t concerned with fields at all.
Also unlike each, each:value does not care whether an input value is a tiddler title or not. (“Vanilla” each automatically discards all inputs that don’t correspond to tiddler titles, since — by definition — a tiddler that does not exist does not have any fields.)
It cannot take a parameter (other than, technically, each:value[title]).
each:value[tags] = each[tags] → the :value suffix is ignored.
each:value[title] = each:value[] → probably for the same reason that [[missing tiddler]] :filter[{!!title}] returns [[missing tiddler]]; {{!!title}} and <<currentTiddler>> both yield the string output of the filter, whether or not that string corresponds to an actual tiddler with a title field.
Again, I don’t know why you’d use each:value[] when unique[] exists. EDIT: Because it’s (sometimes considerably) more efficient, as I discovered later in this thread.
That was a bad guess on my part. This has nothing to do with each/forEach found in JS itself or certain libraries. While I see reasonably well now what it does, I have no real idea why it exists. Does anyone have real-world examples of using each?
In this case, I’m using the source field to store a single title only, so each[source]get[source] is appropriate. But elsewhere in my wiki, I also use an authors field which uses title-list format. For instance:
title: The Elements of Style
authors: [[Strunk, William Jr.]] [[White, E. B.]]
If I wanted a list of all the authors represented in my wiki, I’d use [each:list-item[authors]sort[]].
Interesting. Is there an advantage to this over [get[field]unique[]]?
Damn, that looks like it could be useful! Do you have to do any more than add that stylesheet and use your code? My initial attempt only shows the SELECT, without the text input.
Here’s the data from Maurycy’s Advanced Performance plugin. I ran each filter three times, and you can see that the each filter is consistently more efficient at scale—though the difference may be less noticeable in a smaller wiki.
Edit: Just for fun, I also compared [each:list-item[field]] with [get[field]enlist-input[]unique[]]:
… but again, each wins out. So I suppose the reason to use it over other constructions that yield the same results is simply: efficiency! And I may need to go refactor some code now.
I end up tweaking nearly all the code I borrow, so it’s very possible I’ve changed it in some incompatible way. Here’s the .combobox style from my own stylesheet:
.combobox {
--dropdown-button:20px;
position: relative;
display: inline-flex;
padding-right: var(--dropdown-button);
background-color: #fafaf9;
border-radius: 5px;
width: 10em;
}
.combobox input {
background-color: #fafaf9;
width: 10em;
}
.combobox select {
position: absolute;
/*the width of the select will be the width of the dropdown*/
width: 100%;
/*select is hard to style, so we clip the size we want and hide it, then show a pseudo-element above it*/
opacity:0;
clip-path: inset(0 0 0 calc(100% - var(--dropdown-button)));
pointer-events:all;
cursor:pointer;
}
In my wiki, that looks like this:
Tested on TW-com, the dropdown caret isn’t visible, but you can type into the input field, and clicking at the right end of the box brings up the dropdown. I’ve restyled the base input elements in my wiki, and I suspect that accounts for the difference; you may need to adjust the width/positioning to get things to line up properly.
I like these examples as they are easy to understand, and no other concept is required to know in advance. Those given in the PR are very difficult (they are good for advanced users)
I’m sorry. I didn’t mean to give you an assignment. But thank you very much for checking on this.
Clearly each is valuable. All the more reason to ensure that it’s well-documented!
That works for me, subject the arrow-visibility caveat you mention. Thank you very much for sharing. I can see several similar uses of my own for such comboboxes.
There is a bug in the each[] filter implementation. I am having a closer look at this one at the moment.
I also think it is necessary to have a closer look, where the each[] operator was used the first time in the TW core. This points to the main usecase it was developed for.
So the each-operator help from TW v5.1.0 points us into the right direction. That’s the whole purpose this operator was developed for. So it basically is a helper operator to create “typed-lists”
Well, an [each[coror]] filter can’t produce a tiddler with a color field. But since the screenshot shows the correct version, this seems to be just an unfortunate typo that very likely got propagated from the issue title into the first post via copypaste.
I agree that the 5.1.0 documentation is less confusing.
For users that can read JavaScript or C-like languages and are willing to dig into the TW test code, it is always worth to have a closer look at the TW test edition
Many of the test in the test-edition are part of the TW documentation. But not all of them.
This should be no excuse for missing documentation, but it can help to improve the documentation for those who are able and willing to dig the “rabbit hole”.
You are right. That’s an inconsistency which has potential for more confusion. – It may or may not be fixed. – At the moment I am not sure if it should be fixed.
The implementation of the each-operator is a bit tricky at the moment. It contains nested if()s that are hard to read and debug. From my point of view it should be rewritten.
That’s a very interesting catch, but understandable. Running each[] does all it’s work in 1 run. So if used in the right way it can be an improvement for slow filters that need unique lists.
The unique[] filter needs to go through a potentially large list 2 times. We already know that it can be a performance killer.
IMO, it doesn’t need to be. It’s a little odd that each:value[title] is the one exception. But it is consistent with both
each[] = each[title] (and the current docs, where title is explicitly called out as the default parameter for each)
and the way TW uses title as equivalent to “the input string”, generally speaking: [title[missing title]] returns “missing title”, even though [field:title[missing title]] does not.
I think it’s a pretty obscure exception, anyway. I didn’t remember having seen each:value in the wild before (in fact, I had forgotten it existed at all before this thread prompted me to read the docs more closely), and a Google search for “each:value[” tiddlywiki just now only turned up two or three real results, including this thread.
This was my intuition too, but I’m glad to have some numbers to support it—particularly because I also find unique[] much more semantically obvious, and I’ve never seen each:value[] explicitly recommended instead, even though it would be a more efficient 1-to-1 substitution.
If each does get rewritten, I hope the better performance can be preserved!