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