Here is my function:
\function test-bg(param:empty)
[<param>match[low]then[skyblue]]
:else<param>match[medium]then[purple]]
:else<param>match[high]then[red]]
:else<param>match[critical]then[gray]]
\end test-bg
How do you pass a field value to a function parameter? I have been trying differnet ways to do it but was unsuccessful.
For example this does not work:
<<test-bg {{!!task-priority}}>>
Ironically, you can call a function using the $macrocall. Is that a valid way of doing it?
<$macrocall $name=test-bg value={{!!task-priority}} />
Yes, you can use filtered transclusion with function using the macrocall widget, or with the transclude widget.
If you use at least one . in your function name, you can treat the function as a custom operator:
\function test.bg(param)
[<param>match[low]then[skyblue]]
~[<param>match[medium]then[purple]]
~[<param>match[high]then[red]]
~[<param>match[critical]then[gray]]
\end
This gives you some additional flexibility in parameter usage:
{{{ [test.bg{!!task-priority}] }}} or <$text text={{{ [test.bg{!!task-priority}] }}} />
{{{ [test.bg[high]] }}}
<$let variable="high">
{{{ [test.bg<variable>] }}}
</$let>
This is a general limitation of the <<short-form>> syntax shared by functions, procedures, and macros: in each case, they can only take literal strings as (named or sequential) parameters. So while <<test-bg {{!!task-priority}}>> isn’t valid, the following parameters are..
<<test-bg high>>
<<test-bg param:"high">>
And as you guessed, the following are both valid long-form “function-calls”:
<$macrocall $name=test-bg value={{!!task-priority}} />
<$transclude $variable=test-bg value={{!!task-priority}} />
I don’t typically find the widget syntax very useful for working with functions, though; it doesn’t lend itself to use in filters or attribute values. And conversely, all the above examples do still work with test.bg rather than text-bg, so there’s no real downside to using periods in your function names.
Another approach is to just turn it into a variable first;
\function test-bg()
[<param>match[low]then[skyblue]]
:else<param>match[medium]then[purple]]
:else<param>match[high]then[red]]
:else<param>match[critical]then[gray]]
\end test-bg
<$let param={{!!task-priority}}>
<<test-bg>>
</$let>
Then remove param as a parameter (perhaps also rename param to task-priority). The function will “inherit” the variable unless it is defined, as test.bg(param) effectively defines param inside the function.
However I do favor using functions and custom operators.
Another approach
Depending on if you want to reuse your function to access other fields, you could just pass the fieldname
\function myfunc(fieldname) ....
<<myfunc fieldname>> and use [all[current]get<fieldname>... instead of the hardcoded {!!fieldname}
I couldn’t get the “inherit” mechanism to work. Every time I had to explicitly declare the parameter.
I am curious about your " Another approach" but I do not understand it.
I was able to find a working solution, I am building a task workflow and wanted the priority dropdown to be colored based on values. I had to use style.* in the $select macro because the CSS modpri was not dynamically changing (when it was, it was applying to all tiddlers calling tm-module-priority.
Here is my tiddler, tagged with $:/tags/Macro:
\procedure tm-module-priority()
<$select field="task-priority" class="modpri" default="Choose Priority" style.background-color={{{[priority.color{!!task-priority}]}}} >
<option class="modpri" disabled>Choose Priority</option>
<option class="modpri" style.background-color={{{ [priority.color[low]] }}}>low</option>
<option class="modpri" style.background-color={{{ [priority.color[medium]] }}}>medium</option>
<option class="modpri" style.background-color={{{ [priority.color[high]] }}}>high</option>
<option class="modpri" style.background-color={{{ [priority.color[critical]] }}}>critical</option>
<style>
.modpri {
color: white;
font-weight: bold;
}
</style>
\end
\function priority.color(param:"empty")
[<param>match[empty]then[black]]
:else[<param>match[low]then[skyblue]]
:else[<param>match[medium]then[blue]]
:else[<param>match[high]then[red]]
:else[<param>match[critical]then[gray]]
\end
That’s because your function has a named parameter of the same name. Here, you’re explicitly redefining the <<param>> variable as either the declared value or “empty”:
\function test-bg(param:empty)
But even if you didn’t provide a fallback value, it would be redefined as blank if not explicitly declared:
\function test-bg(param)
If you want the <<param>> value to be inherited from an existing variable <<param>>, you need to omit it from the function parameters, as Tony did (edited to add the missing brackets):
In this case, you might also want to build your fallback value into the function — and you can do this with filter logic, without defining a default “empty” value:
\function test-bg()
[<param>match[low]then[skyblue]]
:else[<param>match[medium]then[purple]]
:else[<param>match[high]then[red]]
:else[<param>match[critical]then[gray]]
:else[[black]]
\end
or
\function test-bg()
[<param>match[]then[black]]
:else[<param>match[low]then[skyblue]]
:else[<param>match[medium]then[blue]]
:else[<param>match[high]then[red]]
:else[<param>match[critical]then[gray]]
\end
As a side note, I don’t generally see much value in defining a parameter fallback like “empty” unless you need the visual cue for temporary testing purposes; since we have filter operators like match[] or is[blank], a null value is itself a value. So even in cases where I do want an explicitly declared parameter without a “meaningful” default value, I’d typically define it like this:
\function test-bg(param)