UIBUILDER asyncSend and ESM use

To change the subject back to uibuilder :rofl:

I am trying to use asyncSend() - just because - but I am obviously not doing it right because although the send part works OK I am not getting a response (well I do but not as part of the .then response)

This is what I have

function fetchApplianceData(applianceName) {
    console.log('Appliance Name:', applianceName)
    uib.asyncSend({ topic: 'fetch/attributes', payload: applianceName })
        .then (response => {
                uib.set('responseAttributes', msg.payload)
                console.log('Response:', response)
            })

        .catch (err => console.error('Failed:', err))

}

So I get the applianceName, then silence. What am I doing wrong?

Not only, but also - not a big issue but a niggle.

I have a uibuilder.set('buttonText', buttonData.label[checkedState]) as part of a function to set up a <form> and <span uib-var="buttonText"></span> to label a button in that form. When I reload the browser page I get

Evaluation attempt 1 failed: buttonText is not defined four times.

I am using <script type="module" async src="./index.js"></script> to load index.js and then import { uibuilder } from '../uibuilder/uibuilder.esm.min.js at the top of index.js.

How do I stop this?

I'm struggling to follow the logic to be honest, can you share the html? Maybe a simplified version if your live one is big.

I have spotted a something in your code though. uib.set('responseAttributes', msg.payload) where is msg coming from? It is not in the code you've shared.

OK, this is cutdown version of the HTML

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="../uibuilder/images/node-blue.ico">

    <title>Blank template - Node-RED UIBUILDER</title>
    <meta name="description" content="Node-RED UIBUILDER - Blank template">

    <!-- Your own CSS (defaults to loading uibuilders css)-->
    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet">


    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->

    <!--  OPTIONAL: Put your custom code here -->
    <script type="module" async src="./index.js"></script>

    <!-- #endregion -->

</head>

<body>

    <h1>Dialog With Form</h1>
    <div role="doc-subtitle">Using UIBUILDER for Node-RED</div>

    <div class="container">
        <button id="btnDownlight01Kitchen" class="button">Kitchen Downlight 01</button>

        <dialog id="dialogDeviceData">

            <form id="formInput" method="dialog">
                <!-- Data entry part of <form>  -->
                <fieldset>
                    <legend>Controls</legend>
                    <div>
                        <label for="buttonOnOff">Lamp State</label>
                        <button
                                type="button"
                                id="buttonOnOff"
                                name="onOff"
                                data-attribute="OnOff">
                                <span id="buttonIcon"></span>
                                <span uib-var="buttonText"></span>
                        </button>

					</div>

                </fieldset>

                <div>
                    <button id="btnSubmit" value="submit">Close</button>

                </div>

            </form>

        </dialog>

    </div>

</body>

</html>

and the uib.set is from;

uibuilder.onTopic('response/attributes', (msg) => {
    uibuilder.set('responseAttributes', msg.payload)

})

The logic is that I send a msg. from uibuilder, a function then actions a response and returns the answer which is monitored by the above & document.addEventListener('uibuilder:propertyChanged:responseAttributes', (event) => {

As I said in a previous message, I currently use uib.send({topic: '..', payload: '..'}) which works but I just HAD to try the asyncSend() method.

OK, so I worked up a quick ESM-based demo of asyncSend. I had to remind myself how it worked! I don't use it myself as it was a request for a specific use-case that I've not come across myself.

The most important thing to note is that you MUST send back a message with the same msg.topic AND the same msg._uib.correlationId as the msg that Node-RED receives. In the example, I've simply looped the received msg back into the uibuilder node with just a quick change to the payload.

[{"id":"fa0240a25588cf67","type":"group","z":"b2f18a716bd20f99","name":"Quick asyncSend function demo","style":{"label":true},"nodes":["e51ba7ef3e333151","a86aea213a59fe7d","2d170e4ebc0b7f1f","fa56099adb3acf7e","3dc0031905a11e96","7fc5dc8d632aca16","b0661e7aef09d16f","24be6cd926d1deb0"],"x":88,"y":1459,"w":648,"h":328},{"id":"e51ba7ef3e333151","type":"debug","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":655,"y":1500,"wires":[],"l":false},{"id":"a86aea213a59fe7d","type":"uibuilder","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"","topic":"","url":"becker","instancePath":"","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":true,"sourceFolder":"src","deployedVersion":"7.7.0","showMsgUib":false,"title":"","descr":"","editurl":"vscode://file/D:/src\\uibRoot/becker/?windowId=_blank","x":300,"y":1540,"wires":[["2d170e4ebc0b7f1f"],[]]},{"id":"2d170e4ebc0b7f1f","type":"switch","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"query","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":450,"y":1520,"wires":[["e51ba7ef3e333151","3dc0031905a11e96"],["fa56099adb3acf7e"]]},{"id":"fa56099adb3acf7e","type":"debug","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"debug 33","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":565,"y":1560,"wires":[],"l":false},{"id":"3dc0031905a11e96","type":"link out","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"link out 62","mode":"link","links":["7fc5dc8d632aca16"],"x":695,"y":1540,"wires":[]},{"id":"7fc5dc8d632aca16","type":"link in","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"link in 19","links":["3dc0031905a11e96"],"x":135,"y":1540,"wires":[["b0661e7aef09d16f"]]},{"id":"b0661e7aef09d16f","type":"change","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"RESPONSE","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":195,"y":1540,"wires":[["a86aea213a59fe7d"]],"l":false},{"id":"24be6cd926d1deb0","type":"group","z":"b2f18a716bd20f99","g":"fa0240a25588cf67","name":"RUN ONCE: Initialise Front-end Code - Run after the uibuilder node has been deployed. \\n REMEMBER to change the uib node name before use \\n Sets up FE code, reloads connected clients. \\n ","style":{"label":true,"stroke":"#a4a4a4","fill-opacity":"0.33","color":"#000000","fill":"#ffffff"},"nodes":["54afea71bcf96374","c1d30ee72e72cbb0","c92d83bda675832c","5bcce172317b7bfd","34ff3e8e97de6fd5","5763fbb206b384ed"],"x":114,"y":1591,"w":554,"h":170},{"id":"54afea71bcf96374","type":"inject","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"setup all FE files","x":175,"y":1680,"wires":[["34ff3e8e97de6fd5","5763fbb206b384ed"]],"l":false},{"id":"c1d30ee72e72cbb0","type":"template","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","name":"index.html","field":"payload","fieldType":"msg","format":"html","syntax":"plain","template":"<!doctype html>\n<html lang=\"en\"><head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/uib-world.svg\" type=\"image/svg+xml\">\n\n    <title>asyncSend demo - Node-RED UIBUILDER</title>\n    <meta name=\"description\" content=\"Node-RED UIBUILDER - asyncSend demo\">\n\n    <!-- Your own CSS (defaults to loading uibuilders css)-->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <script type=\"module\" async src=\"./index.js\"></script>\n</head><body>\n    <h1 class=\"with-subtitle\">asyncSend demo</h1>\n    <div role=\"doc-subtitle\">Using UIBUILDER for Node-RED</div>\n\n    <!-- '#more' is used as a parent for dynamic HTML content in examples\n         Also, send {topic:\"more\", payload:\"Hello from <b>Node-RED</b>\"} to auto-display the payload -->\n    <div id=\"more\" uib-topic=\"more\"></div>\n\n    <article>\n        <button id=\"btn1\" type=\"button\" onclick=\"sendMe(event)\">Send Message to Node-RED</button>\n    </article>\n</body></html>","output":"str","x":380,"y":1680,"wires":[["c92d83bda675832c"]]},{"id":"c92d83bda675832c","type":"uib-save","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","url":"becker","uibId":"a86aea213a59fe7d","folder":"src","fname":"","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"","topic":"","x":550,"y":1680,"wires":[]},{"id":"5bcce172317b7bfd","type":"template","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","name":"index.js","field":"payload","fieldType":"msg","format":"javascript","syntax":"plain","template":"// Give VS Code IntelliSense for uibuilder\n/// <reference path=\"../types/uibuilder.d.ts\" />\n\n// @ts-ignore\nimport { uibuilder } from '../uibuilder/uibuilder.esm.min.js'\n\nwindow.sendMe = (event) => {\n    uibuilder.asyncSend({ topic: 'query', payload: 'test' })\n        .then((/** @type {any} */ response) => {\n            console.log('Response:', response)\n        })\n        .catch((/** @type {any} */ err) => {\n            console.error('Failed:', err)\n        })\n}\n","output":"str","x":390,"y":1720,"wires":[["c92d83bda675832c"]]},{"id":"34ff3e8e97de6fd5","type":"change","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","name":"index.html","rules":[{"t":"set","p":"fname","pt":"msg","to":"index.html","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":265,"y":1680,"wires":[["c1d30ee72e72cbb0"]],"l":false},{"id":"5763fbb206b384ed","type":"change","z":"b2f18a716bd20f99","g":"24be6cd926d1deb0","name":"index.js","rules":[{"t":"set","p":"fname","pt":"msg","to":"index.js","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":265,"y":1720,"wires":[["5bcce172317b7bfd"]],"l":false},{"id":"3152d3dea31807f2","type":"global-config","env":[],"modules":{"node-red-contrib-uibuilder":"7.7.0"}}]

For reference:

index.html

<!doctype html>
<html lang="en"><head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="../uibuilder/images/uib-world.svg" type="image/svg+xml">

    <title>asyncSend demo - Node-RED UIBUILDER</title>
    <meta name="description" content="Node-RED UIBUILDER - asyncSend demo">

    <!-- Your own CSS (defaults to loading uibuilders css)-->
    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

    <script type="module" async src="./index.js"></script>
</head><body>
    <h1 class="with-subtitle">asyncSend demo</h1>
    <div role="doc-subtitle">Using UIBUILDER for Node-RED</div>
    
    <!-- '#more' is used as a parent for dynamic HTML content in examples
         Also, send {topic:"more", payload:"Hello from <b>Node-RED</b>"} to auto-display the payload -->
    <div id="more" uib-topic="more"></div>

    <article>
        <button id="btn1" type="button" onclick="sendMe(event)">Send Message to Node-RED</button>
    </article>
</body></html>

index.js

// Give VS Code IntelliSense for uibuilder
/// <reference path="../types/uibuilder.d.ts" />

// @ts-ignore
import { uibuilder } from '../uibuilder/uibuilder.esm.min.js'

window.sendMe = (event) => {
    uibuilder.asyncSend({ topic: 'query', payload: 'test' })
        .then((/** @type {any} */ response) => {
            console.log('Response:', response)
        })
        .catch((/** @type {any} */ err) => {
            console.error('Failed:', err)
        })
}

Ooops. That was the answer. I was changing the topic. Sorry about that - what a muppet !!! :flushed_face:

The most embarrassing part of this is that this was stressed in the ref

Topic must be preserved. (Mentioned in the second line of your code, but foolishly overlooked on my part while taking it all in.) Not only does the asynSend() match on ._uib.correlationId, but the topic must also be preserved rather than modified/mutated. If the topic no longer matches - despite matching correlationId - the message coming into uibuilder will not be associated with the asyncSend().then(). In the context of a NavGuard where the flow/DB logic may want to mutate the topic (E.g. Change the topic to topic:'router/switch'), this sort of message manipulation has to remain "packed" elsewhere in the message then expanded within the asynSend().then() hander.

Thank you for your patience over the weekend. As you can tell I have only just started with uibuilder (again) and I am trying different things out. I am having fun trawling the web for answers to ways of achieving what I want the page to look like.

No problem, keeps me on my toes. :slight_smile:

And that is the main thing! :grinning_cat: