Actions Attribute of Button Widget and Actions Macro

Actions in Button Widget and Action Macro: Call Macro Directly or Put Macro Call in Triple Double Quotes

  1. open https://tiddlywiki.com
  2. create a tiddler with below text
\define my-action(param)
<$list filter="[<par01>addprefix[my literal string ]addprefix<__param__>]">
<$action-setfield $tiddler=test01 $field=text $value=<<currentTiddler>> />
</$list>
\end

<$let par01="Hello Tiddlywiki" par02>
<$button actions=<<my-action "my passed attribute">> > Do it</$button>
</$let>


{{test01}}

The above code does not work. On click, test01 is updated with wrong text value. The param passed seems to be ignored.

Now change the $button as below

<$button actions="""<<my-action "my passed attribute">>""" > Do it</$button>

Now this modified code works as expected (note to triple quotes). What is wrong here?

In the first syntax (actions=<<my-action "my passed attribute">>) the macro call is being replaced by the macro content when the $button widget is rendered. Thus, the value of the actions=... is effectively:

<$button actions="""<$list filter="[<par01>addprefix[my literal string ]addprefix<__param__>]">
<$action-setfield $tiddler=test01 $field=text $value=<<currentTiddler>> />
</$list>""" > Do it</$button>

Then, when the $button is clicked, the action code is no longer an actual macro call and, as a result, the <__param__> syntax doesn’t have a value (since that syntax only works when contained inside a macro definition).

In contrast, in the second syntax (actions="""<<my-action "my passed attribute">>""") the macrocall is defined as literal text that is only invoked (and wikified) when the $button widget is actually clicked. Thus, a true macro call is occurring, and the <__param__> value is properly set to the param value passed into the macro.

Another way this can be made to work is to use addprefix[$param$] instead of addprefix<__param__>. This performs a direct text substitution into the macro content which then replaces the macro call in the action=... parameter of the $button widget. Then, when the $button is clicked, the passed attribute is a literal text value that has already been inserted directly into the filter syntax.

-e

3 Likes

Thank you Eric for your clarification.

1 Like

Thanks @EricShulman for that explanation.
So, what does that mean performance-wise? Especially for more complex actions, or when there are many instances of a button, there will be fewer widgets initially rendered when we use the """ syntax, right? The macro call will then only be wikified when the button is clicked.

Have a nice day
Yaisog

The widgets in the actions are only parsed and rendered when the actions are invoked. However, if the actions are assigned via a macro, the macro is processed when the button widget is rendered. If you are not passing parameters to your macros, you really don’t need to concern yourself with this.

The thing to avoid is action widgets in the body of a button or other invoking widget, which are rendered each time the surrounding widget is rendered and also refreshed as part of every refresh cycle.

2 Likes

Thanks for the clarification.

This is also the solution to a problem that stumped me every now and then: How to pass a variable to a macro call in the actions attribute. With the """ syntax, this

\define actions(text)
<$action-sendmessage $message="tm-notify" $param=<<__text__>> />
\end

<$let variable="SampleNotification">
<$button actions="""<$macrocall $name="actions" text=<<variable>> />""" >
Click Me
</$button>
</$let>

works. Without it, there is no way to get that text variable assigned. Sometimes, when applicable, I referenced <<variable>> directly in the $param attribute of the macro (or wherever I needed it), but that just doesn’t yield very pretty code and often requires scrolling to find where that variable has been set.

I’m definitely gonna put that into my bag of tricks.

Thanks again, @EricShulman and @saqimtiaz!

1 Like

And definitely worth to be shared with community under ‘Tips & Tricks’ :wink:

@Mohammad: Are you suggesting I do that, or are you volunteering to do that?

Have a nice day
Yaisog

Yes, please! You said you are going to add this to your tips! I asked if you kindly share this with community under Tips & Tricks.

Thank you!

Based on the above discussion, the below solution is a not a good practice, am I right?

[tw5] Just some coding fun: Tiddler Word Count on Demand - Google Group (Read Only) - Talk TW (tiddlywiki.org)

Last Word Count: <$text text={{{ [[$:/temp/WordCount]get[text]addsuffix[ words found at ]else[waiting on button to be clicked]] }}}/><$text text={{{ [[$:/temp/WordCount]get[modified]format:date[0hh:0mm:0ss]] }}}/>

<$button>
<$action-setfield $tiddler="$:/temp/WordCount" text={{{ [!is[system]get[text]splitregexp[\s+]count[]] }}}/>
Update Word Cound
</$button>

Read the Saq explanation above!

Yea, it’s bad practice :wink: … But we still have such code in the core templates. The process to get rid of it is slow, because of our backwards compatibility rules. We don’t want to break older stuff accidentally.

Because … It’s actually a bit more complex then that. As I wrote at: https://github.com/Jermolene/TiddlyWiki5/issues/4272#issuecomment-534493531

The button can look different:

\define ext-actions() .... 

<$button message="tm-close-tiddler" actions="ext-actions">
<$action-xxxxx aaa bbb ccc>
</$button>

Now a UI button has 3 “actions”

  • the “body” actions.
  • The message
  • the ext-actions

The button widget core code executes it in the order shown above. body actions - message - ext-actions

I’m pretty sure, that I did “mis-use” that behaviour in one of my wikis. … So “just” move every action out of a body if it has a message may break some code.

1 Like