Help with adding multiple tags with checkbox to Tasks in Task Manager

So I’ve been working on a task manager inspired by the $:/TagsManager and by other task managers I’ve seen used on other customized tiddlywiki, but I’ve run into a bit of a problem.

I’m trying to set the checkbox widget to, onclick, apply a tag or tags, some of which have spaces in the tag name and require [[brackets]] and while the rest of the task manager is working as intended, whatever change I try to make to get it to work either leads to it showing the tag as [[tag here]] or [[tag (space) here]]

I’ll attach my current tiddlers so you can just drag/drop them into a blank TW and see what I mean.

TaskManagerPluginDemoWIP.json (4.4 KB)

I’m not sure how to fix this, so any input would be appreciated. Worst case scenario, I might have to replace the usage of the checkbox widget with a custom button…

You should pass the checked-tag without brackets, because the tag parameter of the checkbox widget only takes a single tag. Now you need to wrap it in the archive subfilter for that to work properly: "-[[$completed$]] $archived$".

Then do you really want "-$completed$ +$archived$" with archived = "[[Status: Archived]] [[Type: Task]]" to expand to "-$completed$ +[[Status: Archived]] [[Type: Task]]"? Well that doesn’t even matter, because the + filter run prefix doesn’t do what you think it does, it replaces all tags with the archive tags, so you can just remove the +, which will append the tags.

I fixed a few mistakes I’ve made when trying to find a fix, thanks for pointing those out.

So, in order for me to have multiple tags added when clicking the checkbox, I would need to just build my own button, right?

Bit of a bummer, but thank you for the clarification

You can probably do that with the checkactions and uncheckactions attributes of the checkbox widget.

So, I’m 100% doing something wrong here, but I’ve managed to make it half work :sweat_smile:

\define mult-tag-check(done-tags,text)
\define checked()	<$action-listops $field="tags" $subfilter="$done-tags$"/>
\define unchecked()	<$action-listops $field="tags" $subfilter="-$done-tags$"/>

<$checkbox 
uncheckactions=<<unchecked>> 
checkactions=<<checked>> > $text$ </$checkbox>

\end

<<mult-tag-check "[[Status: Done]] [[Type: Task]]" "Hello">>

When I check it, it does apply the tags that I’m aiming to add which is awesome, however, immediately unchecks the box, leaving me a bit confused.

1 Like

Your checkbox isn’t bound to anything at present. Like every other bit of data in TW, the checked state has to be recorded somewhere in a tiddler, or your TW won’t remember that it happened.

Try adding either a tag or a field attribute to the the checkbox widget. Typically this would be one of the values you’re already modifying (tag="Type: Task", perhaps?) but it doesn’t have to be; you could use a field on a completely separate tiddler. (The TW UI tends to use the text fields of tiddlers with the $:/state/ prefix for this purpose.)

ah ok, that makes sense.

Sadly, can’t just use tag=$done-tags$ or tag={{!!tags}}

That’s a bit tricky, since I’m aiming to use this as a button in my task manager, so I’d either need it to add an extra field to each task tiddler, or create a state tiddler for each one.

Not necessarily; the documentation offers at least a couple alternatives.

  • You could use indexes in a $:/state/TaskManager/tasks tiddler; assuming this button is appearing in a list filter that fetches tasks, add tiddler="$:/state/TaskManager/tasks" index=<<currentTiddler>> checked="yes" unchecked="" default="" to your checkbox (and remember to add $tiddler=<<currentTiddler>> to your action macros.)
  • Try one using the new-ish listField or filter modes instead (in either case, you’d be looking at the tags field of the target tiddler.

Clumsier but simpler:

  • Just pick one of the tags you’re already toggling with $done-tags$ that will be present whenever the checkbox should appear checked, like tag="Type: Task". If you’ve checked the button, the tiddler will have that tag, so it should appear checked.
  • (Least recommended, since it will lead to field pollution) Use a field named for the target tiddler on the Task Manager tiddler itself.

OK, that works!
Well- sort of.

I need to rethink the way this is, because checking it works perfectly fine, but the way I have it set only removes the first tag, which was a design error on my part, so I still have some work to do.

That’s to do with the way macro substitution works. Here’s what substituting those values produces:

\define checked()	<$action-listops $field="tags" $subfilter="[[Status: Done]] [[Type: Task]]"/>
\define unchecked()	<$action-listops $field="tags" $subfilter="-[[Status: Done]] [[Type: Task]]"/>

For the <<checked>> this isn’t a problem, since you’re just adding values. But notice that in <<unchecked>>, the - is applied only to the first filter run. So the macro removes “Status: Done” and then adds “Type: Task” (which is already present, so you see no difference.)

Will you ever need to toggle more than two tags at once? If not, the absolutely easiest solution would be to use one tag as the checkbox binding and the other as the check/uncheck action:

\define mult-tag-check(done-tags,text)
\define checked()	<$action-listops $field="tags" $subfilter="""$done-tags$"""/>
\define unchecked()	<$action-listops $field="tags" $subfilter="""-$done-tags$"""/>

<$checkbox tag="Type: Task"
uncheckactions=<<unchecked>> 
checkactions=<<checked>> > $text$ </$checkbox>
\end

<<mult-tag-check "[[Status: Done]]" "Hello">>

If you do want to allow for more than two tags to be simultaneously toggled, you’ll want to define the full set as a variable before you use it:

\define mult-tag-check(done-tags,text)
\define checked() <$action-listops $field="tags" $subfilter="[subfilter<done-tags>]"/>
\define unchecked() <$action-listops $field="tags" $subfilter="-[subfilter<done-tags>]"/>

<$let done-tags="$done-tags$">
<$checkbox tag="checked"
uncheckactions=<<unchecked>> 
checkactions=<<checked>> > $text$ </$checkbox>
</$let>
\end

<<mult-tag-check "[[Status: Done]] [[Type: Task]]" "Hello">>

(I used tag="checked" there for ease of testing, but you can use whatever checkbox binding you prefer.)

Using the subfilter operator means that the - is applied to the entire filter we’ve defined as “done-tags” (which is itself made up of more than one filter run, with each tag constituting a separate run). So you’re toggling everything the filter outputs, not just the first tag/first filter run.

1 Like

Paramter-as-variable access works fine as well:

\define mult-tag-check(done-tags,text)
\define checked() <$action-listops $field="tags" $subfilter="[subfilter<__done-tags__>]"/>
\define unchecked() <$action-listops $field="tags" $subfilter="-[subfilter<__done-tags__>]"/>

<$checkbox tag="checked"
uncheckactions=<<unchecked>> 
checkactions=<<checked>> > $text$ </$checkbox>
\end

<<mult-tag-check "[[Status: Done]] [[Type: Task]]" "Hello">>
1 Like

This works exactly like I was hoping it would, I can use this to replace the incorrect ones in the Task Manager and hopefully package up into a plugin for others to use if they want.

I had picked up that I wasn’t filtering correctly, but wasn’t aware that there was a subfilter operator. Honestly I was going to look into either making button widget appear like a checkbox

I’m actually not quite sure how parameter as varaiable works, however I see them occasionally in use with plugins, but it’s good to know that they can work as well for this.

I think once I have everything fixed up, I’m gonna need to take a longer amout of time to look into the operators and other filter notation bits.

It does more or less the same thing I did with <$let done-tags="$done-tags$">. Every macro parameter is automatically “predefined” as a variable called <<__parameter__>>, so you can go ahead and use it in that form without defining it. But if you find the format confusing, defining a new variable as I did will obviously work just fine as well.

1 Like

An advantage of using the “parameter-as-variable” syntax, is that it handles instances where a macro parameter value contains a quote character ("). For example, suppose you wrote:

\define mymacro(myparam)
<$let myvar="$myparam$">
...
\end

For most parameter values, this would work just fine. But if you were to pass in a parameter that contains a double-quote (e.g., This has "quoted" text in it), then the TWCore macro processing would first replace the occurence of $myparam$ with the passed in value, effectively resulting in:

<$let myvar="This has "quoted" text in it">

which would be incorrectly parsed, since the first double-quote contained in the parameter value would be seen as a delimiter that ends the quoted text being assigned to myvar, causing the value of myvar to be truncated to just “This has

In contrast, if you were to use the “parameter-as-variable” syntax:

<$let myvar=<<__myparam__>>>

then the double-quote contained in the parameter value wouldn’t break the $let assignment, and the resulting value of myvar would be This has "quoted" text in it, just as you would expect.

Note that for some use-cases there is still an advantage to using the $myparam$ syntax. For example, it’s much easier to concatenate text values using the $myparam$ syntax, like this:

<$let myvar="The input is $myparam$">

as compared to using the parameter-as-variable syntax, which would need to use “filtered transclusion” to construct the desired text:

<$let myvar={{{ [[The input is ]addsuffix<__myparam__>]] }}}>
or
<$let myvar={{{ [[The input is ]] [<__myparam__>] +[join[]] }}}>

enjoy,
-e

3 Likes

But if there is any chance the content contains Any common quotes the tripple quoted paramaterd also work “”"$parameter$""" as well. In part this is good because tripple quotes tend not to appear anywhere else.