# Does ui-template script have access to context?

**URL:** <https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994>\
**Category:** Dashboard\
**Created:** [14 September 2021 00:27 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994 "2021-09-14T00:27:38Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![chris.willing](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/chris.willing/32/76579_2.png) [@chris.willing](https://discourse.nodered.org/u/chris.willing)\
**Post date:** [14 September 2021 00:27 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/1 "2021-09-14T00:27:38Z")

</div>

I have a ui-template node in which I'd like to access some data using flow.get() from within script tags. Should that be possible? I have a very simplified flow to test that with just a plain varaiable but it doesn't work - execution stops doing flow.get()

```auto
[{"id":"5f1dce96.0c0ea8","type":"ui_template","z":"5025a90b.1be418","group":"6646c330.b6a0a4","name":"qwerty","order":0,"width":"10","height":"15","format":"\n\n<style>\n .buttons {\n width: 160px;\n height: 30px;\n }\n [value=\"off\"] {\n /*background-color: #999999;*/\n color: -internal-light-dark(black, white);\n background-color: -internal-light-dark(rgb(239, 239, 239), rgb(59, 59, 59));\n border-color: -internal-light-dark(rgb(118, 118, 118),rgb(133, 133, 133));\n }\n [value=\"on\"] {\n /*background-color: #000000;*/\n color: -internal-light-dark(black, white);\n background-color: rgb(178, 178, 178);\n border-color: -internal-light-dark(rgb(118, 118, 118),rgb(133, 133, 133));\n }\n .holder {\n display: flex;\n flex-direction: column;\n }\n .deviceList { /* A set of radio buttons */\n background-color: #a1a1a1;\n min-height: 200px;\n min-width: 490px; \n margin-top: 10px;\n margin-bottom: 10px;\n }\n .deviceList input[type=\"radio\"] {\n display: none;\n }\n .deviceList label {\n display: flex;\n flex-direction: column;\n background-color: #a1a1a1;\n padding: 4px 11px;\n font-family: Arial;\n font-size: 16px;\n cursor: pointer;\n }\n .deviceList input[type=\"radio\"]:checked+label {\n background-color: #76cf9f;\n }\n .readClearDataButtonHolder {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n }\n .alignButtonRight {\n }\n .textArea {\n background-color: #a1a1a1;\n min-height: 220px;\n min-width: 480px; \n margin-top: 10px;\n margin-bottom: 10px;\n resize: none;\n padding: 0;\n }\n</style>\n\n\n<!-- FIND DEVICES -->\n<div id=\"findDevicesButtonHolder\">\n <button id=\"findDevicesButton\" class=\"buttons\">Find devices</button>\n</div>\n<div id=\"deviceListHolder\" class=\"deviceList\">\n</div>\n <!-- DEVICE INFO -->\n<div id=\"infoButtonHolder\">\n <button id=\"infoButton\" class=\"buttons\">Device info</button>\n</div>\n<div id=\"infoAreaHolder\" class=\"infoAreaHolder\">\n <textarea id=\"infoArea\" name=\"infoArea\" class=\"textArea\" rows=\"1\" cols=\"49\" disabled></textarea>\n</div>\n <!-- DEVICE DATA -->\n<div id=\"readClearDataButtonHolder\" class=\"readClearDataButtonHolder\">\n <div class=\"alignButtonLeft\">\n <button id=\"readDataButton\" class=\"buttons\" value=\"off\">Read data</button>\n </div>\n <div class=\"alignButtonRight\">\n <button id=\"clearDataButton\" class=\"buttons\">Clear</button>\n </div>\n</div>\n<div id=\"dataAreaHolder\" class=\"dataAreaHolder\">\n <textarea id=\"dataArea\" name=\"dataArea\" class=\"textArea\" rows=\"1\" cols=\"49\" disabled></textarea>\n</div>\n\n<script>\n (function(scope) {\n let timer;\n \n infoButton.addEventListener('click', function (e) {\n if (event.detail === 1) {\n timer = setTimeout(() => {\n infoArea.value = infoArea.value + \"\\nCLICK\";\n }, 300);\n }\n });\n infoButton.addEventListener('dblclick', function (e) {\n clearTimeout(timer);\n infoArea.value = infoArea.value + \"\\nDBLCLICK\";\n });\n \n scope.$watch('msg', function (msg) {\n if (msg.payload == \"newDevice\") {\n dataArea.value = dataArea.value + \"\\nAAA \" + msg.payload;\n\n // Testing flow context here\n var avar = flow.get(\"atest\") || 5;\n dataArea.value = dataArea.value + \"\\nZZZZZ \" + avar;\n\n \n }\n });\n \n \n })(scope);\n \n</script>\n\n\n\n\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":670,"y":200,"wires":[[]]},{"id":"6646c330.b6a0a4","type":"ui_group","name":"Default","tab":"ba47fdb1.029a08","order":1,"disp":false,"width":"10","collapse":false},{"id":"ba47fdb1.029a08","type":"ui_tab","name":"X-keys Device Finder","icon":"dashboard","disabled":false,"hidden":false}]

```

even though context tab in right side bar correctly displays availability of the "atest" flow context. When injecting a newDevice event, I would expect the script in the ui-template to access "atest" (as set by "set/log context var" function node) and display the value in the bottom text area of the dashboard display.

Presuming that context is not available from within the script tags, is there an alternative method to share access to objects between nodes? The test flow uses just a simple variable but my real world usage involves a reasonably complex object.

Thanks for any advice,  
chris

---

<div class="post-metadata">

**Author:** ![Andrei](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/andrei/32/10446_2.png) [@Andrei](https://discourse.nodered.org/u/Andrei)\
**Post date:** [4 October 2021 03:59 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/2 "2021-10-04T03:59:50Z")

</div>

> [@chris.willing](#):
>
> Presuming that context is not available from within the script tags

Right, the context is not available inside the script tags (hence you got an error in browser console stating that Flow is not valid or something like that). Keep in mind that the code inside the script is running in the browser. Your nodes are part of a Node.JS application running in your Node-RED instance.

> [@chris.willing](#):
>
> is there an alternative method to share access to objects between nodes?

Well, code running in the browser can use the browser Fetch API to request resources from an HTTP server. You can therefore create an HTTP endpoint in Node-RED that will produce the required object from the context.

Then the alternative method to explore is 1- Create the HTTP endpoint. 2-Make a fetch request inside the script tags.

 ![r1](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/0/f/0fbf3973b2b0fff163ff8729ef33a828792097d6.jpeg)

This is how the code inside the ui\_temple looks like. It is missing error handling to not overcomplicate the explanation.

```auto
<script>

    (function(scope) {
        scope.$watch('msg', function (msg) {
            if (msg.payload == "newDevice") {
                
                async function fetchContext() {
                    fetchResult = fetch('http://127.0.0.1:1880/atest');
                    const response = await fetchResult;
                    const jsonData = await response.json();
                    console.log(jsonData);
                }
            fetchContext();
            }
        });
    })(scope);
    
</script>

```

Testing flow:

```auto
[{"id":"41d2d5e53c0c2d08","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"ca0da7891f7d4a10","type":"http in","z":"41d2d5e53c0c2d08","name":"","url":"/atest","method":"get","upload":false,"swaggerDoc":"","x":160,"y":200,"wires":[["9d606b989fed5e67"]]},{"id":"1110814b9c0934ef","type":"inject","z":"41d2d5e53c0c2d08","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":80,"wires":[["b0b49d39e2eea84b"]]},{"id":"b0b49d39e2eea84b","type":"change","z":"41d2d5e53c0c2d08","name":"","rules":[{"t":"set","p":"atest","pt":"flow","to":"{\"Company\":\"aiot\",\"Name\":\"Andrei Ochmat\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":80,"wires":[[]]},{"id":"9d606b989fed5e67","type":"change","z":"41d2d5e53c0c2d08","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"atest","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":200,"wires":[["d5e48b22b1b9fbdf","c08c04abbe04278b"]]},{"id":"d5e48b22b1b9fbdf","type":"http response","z":"41d2d5e53c0c2d08","name":"","statusCode":"","headers":{},"x":510,"y":200,"wires":[]},{"id":"c08c04abbe04278b","type":"debug","z":"41d2d5e53c0c2d08","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":490,"y":240,"wires":[]},{"id":"478d58c9f20c1f95","type":"ui_template","z":"41d2d5e53c0c2d08","group":"6646c330.b6a0a4","name":"","order":1,"width":0,"height":0,"format":"<script>\n\n (function(scope) {\n scope.$watch('msg', function (msg) {\n if (msg.payload == \"newDevice\") {\n \n async function fetchContext() {\n fetchResult = fetch('http://127.0.0.1:1880/atest');\n const response = await fetchResult;\n const jsonData = await response.json();\n console.log(jsonData);\n }\n fetchContext();\n }\n });\n })(scope);\n \n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":360,"y":340,"wires":[[]]},{"id":"d943c52c82f33c79","type":"inject","z":"41d2d5e53c0c2d08","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"newDevice","payloadType":"str","x":180,"y":340,"wires":[["478d58c9f20c1f95"]]},{"id":"7aba4c506e18f203","type":"comment","z":"41d2d5e53c0c2d08","name":"Store an object in the flow context","info":"","x":230,"y":40,"wires":[]},{"id":"eda547de712428dc","type":"comment","z":"41d2d5e53c0c2d08","name":"Endpoint to expose a way to retrieve the context","info":"","x":280,"y":160,"wires":[]},{"id":"0dfc89e83692a653","type":"comment","z":"41d2d5e53c0c2d08","name":"Example of code that will fetch the URL and get the object from the HTTP server","info":"","x":380,"y":300,"wires":[]},{"id":"6646c330.b6a0a4","type":"ui_group","name":"Default","tab":"ba47fdb1.029a08","order":1,"disp":false,"width":"10","collapse":false},{"id":"ba47fdb1.029a08","type":"ui_tab","name":"X-keys Device Finder","icon":"dashboard","disabled":false,"hidden":false}]

```

Probably not a comprehensive (and still late) response but hopefully can help you move on.

---

<div class="post-metadata">

**Author:** ![chris.willing](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/chris.willing/32/76579_2.png) [@chris.willing](https://discourse.nodered.org/u/chris.willing)\
**Post date:** [4 October 2021 05:38 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/3 "2021-10-04T05:38:04Z")

</div>

Thanks for the reply Andrei. I worked around that particular problem by making the data (that I had wanted to access via context) available with a bigger msg.payload.

However I now have a similar problem, this time with making data from the runtime available to the configuration editor where I'd like to prefill options in a dropdown selector. I have created an HTTP endpoint for that and so far been trying to use `$.getJSON('/xkeys/devices', function(data) {...})` to retrieve the data on the editor side. I have the selector working with pretend options following the TypedInput Select box example at [Node edit dialog : Node-RED](https://nodered.org/docs/creating-nodes/edit-dialog) but can't successfully use real options with the data from $.getJSON yet.

What is the difference between the `$.getJSON` construct and the `fetch('http://127.0.0.1:1880/atest') `method? Any pros/cons worth knowing about?

Thanks again,  
chris

---

<div class="post-metadata">

**Author:** ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)\
**Post date:** [4 October 2021 08:10 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/4 "2021-10-04T08:10:17Z")

</div>

You should use `$.getJSON` rather than `fetch` as the jQuery utility functions are setup to handle authentication if `adminAuth` is enabled.

1. make sure the path you use is namespaced to your node to avoid any potential clashes.
2. in the editor, do _not_ start the path with `/` - so you should use `xkeys/devices`. This ensures the request is relative to the page and will still work if the user has set `httpAdminRoot` to move the root path of the editor.

---

<div class="post-metadata">

**Author:** ![chris.willing](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/chris.willing/32/76579_2.png) [@chris.willing](https://discourse.nodered.org/u/chris.willing)\
**Post date:** [4 October 2021 12:23 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/5 "2021-10-04T12:23:07Z")

</div>

Thanks, I have that working now.

About the adminAuth (which I don't think I need but am curious) - I see in the serial port node, which is often pointed to as an example of making/using an http endpoint, that the call to `RED.httpAdmin.get` has `RED.auth.needsPermission('serial.read')` as one of the parameters. At the reading level it's pretty clear what is intended but what's not clear is who needs the permission to read the serial port? Is it the node (which is doing the reading) or the browser/editor which is asking for the details? Also, what is `serial.read` - where is it set up and what would I use instead of `serial.read` to (dis)allow access for other types of data?

In my case, the data being passed around has been obtained by the node from a separate server which mediates access to the actual devices on the USB bus i.e. the node itself doesn't directly communicate with the devices or the USB bus.

chris

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [3 November 2021 12:23 UTC](https://discourse.nodered.org/t/does-ui-template-script-have-access-to-context/50994/6 "2021-11-03T12:23:59Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
