Asynchronous return in javascript macro

Hi. I am wanting to retrieve a value from a JSON “file” returned via a web service and use it as the value of my macro’s “return.” I am struggling with how to “delay” the return statement until the value has had time to be fetched.

/*\
title: $:/jenn/code-bits/macros/getJSON.js
type: application/javascript
module-type: macro

retrieve values from a JSON web service

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "getJSON";

exports.params = [
    {name: "hex"}
];

/*
Run the macro
*/
exports.run = function(hex) {

let color_url = "https://www.thecolorapi.com/id?hex=" + hex;
let payload = "nope";

function reqListener () {
  console.log(this.response);
  payload = this.response;
}

let xhr = new XMLHttpRequest();
xhr.addEventListener("load",reqListener);
xhr.open('GET', color_url);
xhr.responseType = 'json';
xhr.send();
xhr.onload = function() {
  let responseObj = xhr.response;
  alert(responseObj.hsv.h);
};

return payload;

};

})();

I’m not an expert, but, the usual approach for these situations is:

  • trigger the request (as you are already doing)
  • adjust your reqListener function to put the result of your request, once available, where you need it
  • tell tiddlywiki about the new data, so it can re-render accordingly

it has to be done that way, because if you force everything to wait, you will freeze the whole tiddlywiki while you wait for the response

what I usually do is put the result of the request in a tiddler field, and transclude the tiddler field where I need it

2 Likes