Widget request: Javascript Promise $set widget

I need a widget:

Which lets us specify a javascript tiddler which can be used to call rest apis and insert their results into the rendering of the page. The widget takes its current list of variables and passes it to the Javascript tiddler, then awaits the promise, which should resolve to an object or Map, and sets the key-values as wikitext variables for its children.

It also lets us specify a refresh tiddler which causes the widget to refresh the variables if the rendered plain text of the tiddler changes. If this is expensive it would be reasonable to put some logging in place to make the user aware of how often it is updating, or whatever the TiddlyWiki version of that is.

It should follow the TW5 standard expectations for widgets as it will eventually make its way into the TiddlyWiki core or core-adjacent plugins (or at the very least be used here as a standard widget).

The widget may dictate what form the Javascript code returns inside the promise, but it should expect it to be some kind of list of variables which it makes available to its children.

I do very little with widgets, or even with wikitext, so maybe this already exists.

More details are here: I need a $set widget which gets its variable list from calling a JavaScript function and awaiting a promise · Issue #6 · TiddlyWiki/MultiWikiServer · GitHub

IMO You should have a closer look at: https://tiddlywiki.com/#WidgetMessage%3A%20tm-http-request

Is there a way to dump a json tiddler into variables?

Hi @Arlen22

The approach you outline breaks a couple of the technical constraints that govern widgets:

  • Widgets must perform all their work synchronously. The refresh cycle itself is synchronous for performance reasons, and there’s no path to accommodating asynchronous work
  • Widgets are stateless and volatile. They have no way to maintain state across being torn down and recreated as a result of an ancestor widget needing to be refreshed

As a consequence, the approach you outline would call the rest API every time the widget was refreshed, with no path to caching of the results.

The purpose of variables is that they can have different values at different points in the widget tree, as opposed to tiddlers which have the same value through the widget tree. It sounds like it may be more appropriate in this case to make the results available in a tiddler.

Generally, the most common pattern to tackle these kind of scenarios is a widget message handler on the root widget that listens for messages from buttons etc. instructing it to initiate an HTTP request. The result is then stored in a tiddler. The built-in HTTP handling shows the general structure of the approach.

Here’s a hack way to dump json indexes into variables.

I’m sure there’s a better way to do it, but this works. I’m thinking that a widget would be better than procedure, but I haven’t got my head around custom widgets yet.


\procedure json-to-let(tiddler, body, mode:"block")
  \function fn.make-let(tiddler,varname)[<varname>search-replace:g[ ],[-]addsuffix[="""]] :map[<tiddler>getindex<varname>addsuffix["""]addprefix<currentTiddler>]
  \function fn.json-to-let(tiddler)[<tiddler>indexes[]] :map[function[fn.make-let],<tiddler>,<currentTiddler>] +[join<lf>] 
  \define resolve-body()
    <$let $(varslet)$ ><$transclude $variable="body" mode=<<mode>> /></$let>
  \end resolve-body
  \whitespace trim

<$let varslet={{{ [function[fn.json-to-let],<tiddler>] +[join<lf>]   }}} >

<$transclude $variable=resolve-body />

</$let>
\end

body of “variables-json-tiddler” tiddler:

{
    "day": "today",
    "test var": "test var value"
}

Call procedure:

<$transclude
  $variable="json-to-let"
  tiddler="variables-json-tiddler"
  body="""<div>

|!var |! value |
|day   |<<day>> |
|test-var |<<test-var>> |

</div>""" />

You may be interested in the $setmultiplevariables widget. Here’s an example based on @VikingMage’s sample data:

<$setmultiplevariables
	$names="[[variables-json-tiddler]indexes[]search-replace:g[ ],[-]]"
	$values="[[variables-json-tiddler]indexes[]] :map[[variables-json-tiddler]getindex<currentTiddler>]"
>

|!var |! value |
|day   |<<day>> |
|test-var |<<test-var>> |

</$setmultiplevariables>
1 Like