Action listops toggle

Dear friends,

I have this little piece of code

<$select tiddler='$:/generated-list-demo-state' field='actions-test' multiple size='8' 
actions='<$action-listops  $field="tags1" $subfilter={{$:/generated-list-demo-state!!actions-test}}/>
<$action-listops  $field="tags" $subfilter={{$:/generated-list-demo-state!!actions-test}}/>'
>
<$list filter='[tag[person]]'>
<option><$view field='title'/></option>
</$list>
</$select>

from my, rather limited, understaning it lets you select from all tiddlers tagged “person”, stores the value in a field called “actions-test” in a tiddler called “$:/generated-list-demo-state” then places the value in the tags section of the current tiddler, as well as in a special field called “tags1”.

So far so good. My question is: is it possible to insert a toggle mechanism? Like, if you select a value for a second time to remove it from tags and tags1? i’ve seen the documentation at [https://tiddlywiki.com/static/ActionListopsWidget.html but I don’t understand how to use it in the above code.

Thanks in advance!

I think the idea of a toggle triggered within a select may not be easy to follow.

  • you could modify the filter in the list to make it more sophisticated and perhaps add additional conditional options.

Perhaps explain the workflow if you had the toggle feature you have asked for.

While I agree with @TW_Tones that this is an odd UI (more below), you certainly can do so

<$select tiddler='$:/generated-list-demo-state' field='actions-test' size='8' actions='
  <$action-listops $tags="+[toggle{$:/generated-list-demo-state!!actions-test}]"/> 
  <$action-listops $tags2="+[toggle{$:/generated-list-demo-state!!actions-test}]"/>
'>
<$list filter='[tag[person]]'>
<option><$view field='title'/></option>
</$list>
</$select>

Somehow, though, multiple seems to interfere. I haven’t investigated, though, and there might be a simple solution.

That covers it pretty well. One minor correction: the “tags section” is from this perspective no more or less a special field than tags1. It’s only that in rendering the tiddler that we see any difference.


As to the usability, I find this somewhat strange. You can add a person by selecting the name from the dropdown. But you can’t then immediately remove that name without selecting another one (and thus adding another tag) because that name is already selected. Perhaps if we figure out the multiple bit this wouldn’t be the case; I don’t know. But I think there might be a better UI. In fact, I’ve got one that I just built that might be interesting. I’m not setting tags but another list field, but it should be very similar. Let me try to grab a short video of it (new computer, haven’t tried video capture yet!) If I can, I’ll upload it soon.

Actually, Toggle is in someways how select multiple ALREADY works;

<$select field='actions-test' multiple size='8'>
<$list filter='[tag[TableOfContents]]'>
<option><$view field='title'/></option>
</$list>
</$select>
  • I have kept actions out of this to simplify.

The above example on tiddlywiki gives this result;

  • The actions-test field looks like this Learning [[Working with TiddlyWiki]] [[Customise TiddlyWiki]] Languages

With Multiple select I used;

  • click on Learning to select,
  • Shift-click on Customise to select range,
  • ctrl-cick on Languages to select,
  • You can ctrl-cick on Languages again to deselect, or toggle off

These are the same rules for any list with multiple selections.

  • eg; File managers, File open and save dialogue boxes…
  • Remember the list may be scrollable

When you display the select multiple the currently selected are highlighted.

A more natural way to toggle is with a checkbox widget, and now with the listField parameter we can use the same fieldname above

Add this to the above code and play with it to see other toggle options

<$checkbox listField="actions-test" checked="Languages" unchecked=""> Languages</$checkbox>

<$checkbox listField="actions-test" checked="Features" unchecked="Filters"> Features or Filters</$checkbox>

I believe the only reason you have the actions it to achieve the toggle? With what I showed you it is unnecessary.

However

To reinstate actions the checkbox widget has actions, checkactions and uncheckactions parameters.

  • The Select widget only has actions so you have to include logic for it.

Note since select multiple displays a set number of items you may as well iterate the options with the checkbox widget.

<$list filter='[tag[TableOfContents]]'>
<$checkbox listField="actions-test" checked=<<currentTiddler>> unchecked=""> <$text text=<<currentTiddler>>/></$checkbox><br>
</$list>

You can even make the above scrollable Like the select multiple window

<div style="overflow: scroll; height: 20vh; border: 1px solid gray; padding:5px;">
<$list filter='[tag[TableOfContents]sort[]]'>
<$checkbox listField="actions-test" checked=<<currentTiddler>> unchecked=""> <$text text=<<currentTiddler>>/></$checkbox><br>
</$list>
</div>
  • Although I would like some more styling to make this more obvious for example a larger scroll bar.

Here’s a screen grab of my (very recent, and still incomplete wiki) letting me select a number of people (attendees at a meeting):

Recording 2024-02-27 201417

The relevant code looks like this:

title: $:/_/my/templates/meeting
tags: $:/tags/ViewTemplate

<% if [<currentTiddler>tag[Meeting]] %>

<$let 
  base=<<currentTiddler>>
  by-last="[{!!last-name}] [{!!first-name}] +[join[, ]]"
>

  <!-- display meeting data -->

  <details>
    <summary>Select Attendees</summary>
    <div style="display: flex; flex-flow: row wrap">
      <$list filter="[tag[Member]sortsub:string<by-last>]">
        <$let selected={{{ [<base>contains:attending<currentTiddler>then[selected]else[unselected]] }}}>
            <div class=<<selected>>>
              <div class="selection-card">
                <$button>
                  <$action-listops $tiddler=<<base>> $field="attending" $subfilter="+[toggle<currentTiddler>]"/>
                      <$image class="small avatar" source={{!!avatar}} />
                      <h3>{{!!title}}</h3>
                      <h4>{{!!lichess-id}}</h4>
                </$button>
              </div>
            </div>
        </$let>
      </$list>
    </div>
  </details>
</$let>

<% endif %>

plus some CSS to lay out the card. (This still needs some work, but isn’t terrible):

img.small.avatar {border-radius: 50%; width: 3em; border: 1px solid #ccc; vertical-align: middle;}
.selection-card {border: 2px solid #999;  width: 8em; height: 8em; text-align: center; margin: .25em; background: #f6f6f6;}
.selection-card button {display: block; width: 100%; height: 100%; border: none; padding: .5em; cursor: pointer}
.selected .selection-card {border-color: #0f0;}
.selected .selection-card button {background-color: #efe;}
.selection-card h3 {font-weight: bold; margin: .25em 0; font-size: 90%;}
.selection-card h4 {font-style: italic; margin: .25em 0; font-size: 75%;}

and members that look like this:

title: Scott Sauyet
tags: Member Administrator
avatar: ScottSauyet.jpg
first-name: Scott
last-name: Sauyet
lichess-id: CrossEye

and square jpeg images for the members. I find this a very useful UI. When I’ve tweaked it a bit more, I may try to package it up to share, but the above should show most of the basics.

And of course you don’t need the images or my particular layout, just a simple way to display individual selections in a grid.

3 Likes

A version of this which sets the tags appropriately:

<div style="overflow: scroll; height: 20vh; border: 1px solid gray; padding:5px;">
<$list filter='[tag[TableOfContents]]' variable="item">
<$checkbox listField="tags" checked=<<item>> unchecked=""> <$text text=<<item>>/></$checkbox><br>
</$list>
</div>

But do note the difference between this and the OP’s request. This one takes up a reasonable amount of vertical space. That one gives a control which takes up only a (partial) line of the UI. Only when dropped down does it take up more vertical space. Mine has a similar feature, with the details widget, although that’s not easy to deal with inline. So, for a list with a few dozen entries, if we could get the <select> to work well with actions and toggling the tag values, it would certainly have a place.

I agree limiting the space is useful, My comparison was between select multiple which uses more vertical space and a list of checkboxes. So I was not trying to conserve virtical space beyond allowing selection of the height.

Using my checkbox example this could instead be the content of a dropdown/or is it a popup?,. that accepts similar parameters to the select widget and behaves similarly.

  • This may be a good use case for a custom widget since it is a UI element that we do not want to reuse its output, just display the selection, and set it.

Here is an example of a dropdown select multiple.

  • Set another class to allow only one “toggled at a time”
  • Any filter
  • Any “list” field.
\widget $select.more(filter:"[tag[TableOfContents]]" listField:"tags" class:"tc-popup-keep")
   \function popup-tiddler() [addprefix[$:/temp/alt-tag-popup/]]
<$button popup=<<popup-tiddler>> > Multiple select <<listField>></$button>
<$reveal type="popup" state=<<popup-tiddler>> class=<<class>> >
<div class="tc-drop-down" style.padding="5px">
<$list filter=<<filter>> variable="listitem">
<$checkbox listField=<<listField>> checked=<<listitem>> unchecked=""> <$text text=<<listitem>>/></$checkbox><br>
</$list>
</div>
\end 

<$select.more listField=alt-tags/>

Which can easily be enhanced further.

  • Include scrollable for very long lists?
  • Expandable sections?
  • A list below selection ie slider.

[Fixed] Was one stray ] I have tried to generalise this further but have found a problem calling the same custom widget more than once which suggests a bug Bug or coding error calling custom widgets more than once?

Unlike the above solution designed specifically to have a drop down with checkbox items, I made a generic simple.popup that can contain any content including the list of checkboxes.

\widget $simple.popup(text # class:"tc-popup-keep" label:"More...")
   \function popup-tiddler() [<qualify "$:/state/simple.popup">addsuffix<#>addsuffix[/]]
<$button popup=<<popup-tiddler>> ><<label>></$button>
<$reveal type="popup" state=<<popup-tiddler>> class=<<class>> >
<div class="tc-drop-down" style.padding="5px" >
<<text>>
<$slot $name="ts-raw"/>
</div>
\end $simple.popup

So just a popup with a line of text would be;

<$simple.popup text="more info as text, ie one liners" #=a/>

Or you could use the following inside it to do the same as the previous answer.

<$simple.popup text="Select Tags" #=b>

<$list filter="[tag[TableOfContents]]" variable="listitem">
<$checkbox listField="tags" checked=<<listitem>> unchecked=""> <$text text=<<listitem>>/></$checkbox><br>
</$list>
</$simple.popup>

I also have a select slider widget that simply displays the list below, and move the content.

TW_Tones, Scott, thank you very much!

Perhaps explain the workflow if you had the toggle feature you have asked for.

I was thinking about distributing my project tiddlywiki to colleagues, who would enter the meetings information. But if they made a mistake choosing a meeting attendee they would have to edit the tiddler’s fields in order to correcte it, wich is kind of a leraning curve. Hence the need for some kind of UI.

Here’s a screen grab of my (very recent, and still incomplete wiki) letting me select a number of people (attendees at a meeting):

This looks very good, I’ll experiment with it

Note since select multiple displays a set number of items you may as well iterate the options with the checkbox widget.

Yes, checkboxes make much more sense!

I’ll try your suggestions and code and get back to you. Again, thank you very much!!!

Almost there I think!

I have this

\widget $simple.popup(text # class:"tc-popup-keep" label:"More...")
   \function popup-tiddler() [<qualify "$:/state/simple.popup">addsuffix<#>addsuffix[/]]
<$button popup=<<popup-tiddler>> ><<label>></$button>
<$reveal type="popup" state=<<popup-tiddler>> class=<<class>> >
<div class="tc-drop-down" style.padding="5px" >
<<text>>
<$slot $name="ts-raw"/>
</div>
\end $simple.popup

<$simple.popup text="Select Tags" #=b>

<$list filter="[tag[person]]" variable="listitem">

<$checkbox listField="tags"  
checked=<<listitem>> unchecked=""> <$text text=<<listitem>>/></$checkbox><br>
<$checkbox  listField="people" checked=<<listitem>> unchecked=""> <$text text=<<listitem>>/></$checkbox>

</$list>
</$simple.popup>

But I dont know how to combine the two actions, i end up with two set of checkboxes. The goal is to add/remove the value in two plases, the tags and the custom field called “people”. I tried wrapping the actions in actions=' ' with no luck.

thank you!

While I think this is possible, I’m concerned that having any kind of information stored redundantly, in this way, is probably a bad idea. It will very likely lead you into brittle solutions that depend on everyone knowing that these two things need to be maintained in parallel — and acting consistently on that knowledge!.

(For example, someone who sees a tag for a person, and realizes that it was an error to include that person, may remove the tag without stopping to correct the field list at the same time. I can think of lots of situations where the redundant data would come apart, and you’d have the headache of troubleshooting which list is correct in any such case.)

A data-redundant solution will also be more resistant to efficient further development as your project grows.

If there’s some kind of workflow or user-interface that you think requires storing the participant list in these two redundant places, please share!

Perhaps your view-templates could display something in the tags-display area, say, that also shows the participant list (as stored in the field), in some way that mirrors the function you’re seeking by adding tags for them…

There are some solutions shared here at talk.tiddlywiki.org that have brought some tag-like features to fields. I’m writing in haste now, but others may chime in. Or you could search for threads on this theme.

Before you tried to add the second action was the solution I shared working for you in part?

I was not aware of this need for a second action and I could add it for you, but those are wise words from @Springer, try and avoid putting the same information in two places.

Perhaps you call tell us why you wanted this second action?

  • I expect we can show you filters to find tiddlers with a particular person so you dont need it in tags as well.

Springer, TW_Tones, thanks for your input!

If there’s some kind of workflow or user-interface that you think requires storing the participant list in these two redundant places, please share!

So, the basic idea is that I’m trying to create a template for tiddlers tagged with “meeting” and I need a UI to add participants to those tiddlers. Their names are tiddlers tagged with “person”.

I need those names to tagg the meetings tiddlers because the tiddlymap plugin, wich I’m very much fond of, doesn’t recognize (at least in the LiveView and as far as I can tell) other fields. If the names are tagging the tiddler I can get nice graphs like this one


At the same time I need to be able to view the paricipants names inside the tiddlers body (instead of having people trying to figure them out in the tags section). So I need their names in a special filed, called “people”, in order to write <<list-links “[list[!!people]] +[sort[title]]”>> in the meetings template and get something like

which I suppose I can’t do with tags, because how would I get some script to show me only those specific tags that correspond to people? Hence the need for a special field, wich I assume will be easier to make use of for future needs, especially given that the plan is to use add more categories like people: organization, project’s name etc

While I think this is possible, I’m concerned that having any kind of information stored redundantly, in this way, is probably a bad idea. It will very likely lead you into brittle solutions that depend on everyone knowing that these two things need to be maintained in parallel — and acting consistently on that knowledge!.

Yes, I understand that. In short the redundancy derives from the need to have tiddlymap plugin understand what’s going on and produce those graphs, wich I very much like. Otherwise I would probably have the partisipants stored in a special field, wich I suppose is the most sensible solution. I tried looking at tiddlymap’s code (in order to get it to "read’ from a special field0 but it’s way beyond my skills.

(For example, someone who sees a tag for a person, and realizes that it was an error to include that person, may remove the tag without stopping to correct the field list at the same time. I can think of lots of situations where the redundant data would come apart, and you’d have the headache of troubleshooting which list is correct in any such case.)

So the thought is that people won’t be allowed to edit the meetings tiddlers, only to use the checkboxes UI, which takes care of that: when checked/unchecked both tags and the “people” field are updated.

Before you tried to add the second action was the solution I shared working for you in part?

Yes, perfectly!

I was not aware of this need for a second action and I could add it for you,

please do!

I expect we can show you filters to find tiddlers with a particular person so you dont need it in tags as well.

Indeed. The need for tags has to do with tiddlymap. I even tried the GenTags plugin, which creates separate tag - tag-like sections but tiddlymap doesn’t “see” those either.

Hope this all makes sense and thank you for your time!!!

Try this:

<<list-links "[<currentTiddler>tags[]tag[person]sort[]]">>

Notes:

  • <currentTiddler>tags[] gets all tags for the current tiddler
  • tag[person] filters that result to keep only those tags that are themselves tagged with person
  • you can omit the title operand from the sort[] filter, since that is the default field used for sorting

enjoy,
-e

3 Likes

Yes I see, there are cases where a plugin or other part of our wiki forces our hand, however this should not force our hand, if at all possible, to end up with redundant values. From my experience if I use “unnecessary” redundancy, “it always comes back to bite me”.

  • Its worth the investment in time, in the design phase, than the amount of time it may demand later in maintenance, bugs or updates.

Yes, we can do this. I will show you below. But of course will tiddlymap force your hand also with;

organization, project’s name etc… ?

I understand,

  • Just a friendly warning, list-links is a utility macro, especially good for simple lists, but it makes compromises and can influence your design, when it is possible, to use a $list widget and gain more control.
    • Here you are using it to list people in the people field. We may still use this, in this case, with the right filter.

Grouping tags

When every you have tiddlers that take on some kind of role you need a way to identify these tiddlers apart from others. For example, people tiddlers, could;

  • Have the tag people
    • Tiddlymap forces this for meeting(s), but does it?, for other tags.
  • Have a field such a object-type=people

We can then use these above in filters, including to separate some tags from other tags. However use one or the other as needed not both.

  • If you really had to do both, we can invoke actions that add both (not recommended)

Tagging Tags;

In this case if all your people tiddlers are tagged with people;

You can see all people with;

<$list filter="[tag[people]sort[]]">

</$list>

But if you want to list all tags, on the current tiddler, that are also people use;

<$list filter="[enlist{!!tags}tag[people]sort[]]">

</$list>
  • Un tested now, but should work
  • Note {!!tags} refers to the tags field on the current tiddler.
  • We enlist it to turn it into a list of tiddlers which happen to be tags.
  • So the above filter [tag[people]sort[]] can be used to drive your people selection from all people.

End note

We can add items to the tag pill drop down. Most people will recognise a “person” but we could add an item that describes what that tag represents eg a person. Another method is an Icon on person tiddlers.

  • My reimagine tags utility also allows you to remove a tag, open and close matching tiddlers and more on the tag pill dropdown.
  • Perhaps we could make the ability to remove tags, with reimagine tags conditional, such as they can’t remove the meeting tag (unless its edited)
    • Then to support this we introduce a special “virtual” tag pill, that lists people not on the current tiddler, click to tag.

Thank you very much Eric! If I may ask, is there a way to sort the result based on the second term (the surname)?

TW_Tones thank you, I really appreciate your help and your time!

When every you have tiddlers that take on some kind of role you need a way to identify these tiddlers apart from others. For example, people tiddlers, could;

  • Have the tag people
    • Tiddlymap forces this for meeting(s), but does it?, for other tags.
  • Have a field such a object-type=people

We can then use these above in filters, including to separate some tags from other tags. However use one or the other as needed not both.

  • If you really had to do both, we can invoke actions that add both (not recommended)

Yes, I understand. I’m going with the tag people, it seems easier to use at my skill level.

Tagging Tags;

In this case if all your people tiddlers are tagged with people;

You can see all people with;

<$list filter="[tag[people]sort[]]">

</$list>

But if you want to list all tags, on the current tiddler, that are also people use;

<$list filter="[enlist{!!tags}tag[people]sort[]]">

</$list>

I just now had the time to test, it doesn’t seem to work.

We can add items to the tag pill drop down. Most people will recognise a “person” but we could add an item that describes what that tag represents eg a person. Another method is an Icon on person tiddlers.

I’d be very interested in that. Maybe a separate section containing people, another one containing organizations etc? Definetely with corresponding icons!

will tiddlymap force your hand also with;

organization, project’s name etc… ?

Yes, indeed. Ideally tiddlymap should encounter tags in order to automatically create graphs based on whatever tiddler is open at a time.

  • My reimagine tags utility also allows you to remove a tag, open and close matching tiddlers and more on the tag pill dropdown.
  • Perhaps we could make the ability to remove tags, with reimagine tags conditional, such as they can’t remove the meeting tag (unless its edited)
    • Then to support this we introduce a special “virtual” tag pill, that lists people not on the current tiddler, click to tag.

Just imported and testing the utility, looks great!

I think I’m good to go for the time beeing, with the tags/no redundancy solution.
So, again, thank you all for your help!

\define last-word()
[<currentTiddler>split[ ]last[]]
\end

<$list filter="[<currentTiddler>tags[]tag[person]sortsub<last-word>]"/>

Note this works on the LAST word, rather than the second word. It assumes Anne Marie Jones is a more likely person in your list than José Ortega y Gassett. For the second name, just modify to

\define second-word()
[<currentTiddler>split[ ]nth[2]]
\end

<$list filter="[<currentTiddler>tags[]tag[person]sortsub<second-word>]"/>

Note, the \define line should be the first one in your tiddler. (Other things can come between it and the list widget.)