How to trigger a dropdown for topologies without using the Inject node in Node-RED?

I have the following flow in Node-RED that dynamically loads topologies into a dropdown list:

The flow starts with an Inject node that triggers a function to retrieve the topologies from the global context and display them in a v-autocomplete dropdown.

However, I want to remove the Inject node and trigger the dropdown to load topologies automatically without having to manually inject a signal.

[
    {
        "id": "53f80d6cd7debc1e",
        "type": "inject",
        "z": "de4745db77ed435c",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 130,
        "y": 380,
        "wires": [
            [
                "01a75a924d6d1292"
            ]
        ]
    },
    {
        "id": "01a75a924d6d1292",
        "type": "function",
        "z": "de4745db77ed435c",
        "name": "function 11",
        "func": "const getTopologies = global.get('getTopologies'); // Retrieve the function\nif (!getTopologies) {\n    node.error(\"getTopologies function not found in global context\");\n    return null;\n}\n\n// Define an async wrapper function to handle the async call\n(async () => {\n    try {\n        // Call the getTopologies function\n        const topologies = await getTopologies();\n        console.log(\"Topologies data:\", topologies);\n\n        // Attach the topologies data to the message\n        msg.payload = topologies;\n\n        // Send the updated message\n        node.send(msg);\n    } catch (err) {\n        // Handle any errors\n        node.error(\"Error fetching topologies: \" + err.message);\n    }\n})();\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 310,
        "y": 380,
        "wires": [
            [
                "d94307f94f7b68b6"
            ]
        ]
    },
    {
        "id": "7fd6679aaeecfae0",
        "type": "debug",
        "z": "de4745db77ed435c",
        "name": "debug 2582",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 630,
        "y": 380,
        "wires": []
    },
    {
        "id": "d94307f94f7b68b6",
        "type": "ui-template",
        "z": "de4745db77ed435c",
        "group": "",
        "page": "af4f186e266efab5",
        "ui": "",
        "name": "topo_trial",
        "order": 1,
        "width": "10",
        "height": "6",
        "head": "",
        "format": "<template>\n  <div>\n    <div class=\"msg\">\n      <v-form>\n        <!-- Dynamically populate dropdown options -->\n        <v-autocomplete :items=\"topologies.map(topology => topology.name)\" label=\"Select Topology\"\n          placeholder=\"Search for the topologies\" clearable chips variant=\"underlined\" closable-chips\n          v-model=\"selectedTopology\">\n        </v-autocomplete>\n      </v-form>\n      <div id=\"topology-container\"></div>\n    </div>\n    <link rel=\"alternate icon\" href=\"./favicon.ico\" type=\"image/png\" sizes=\"16x16\">\n    <link rel=\"stylesheet\" href=\"./assets/nextjs/next.css\">\n  </div>\n</template>\n\n<script src=\"./assets/nextjs/next.js\"></script>\n<script>\n  export default {\n        data() {\n            return {\n                topologies: [], // Will be populated dynamically\n                selectedTopology: null, // Selected topology\n                topologyApp: null, // Topology application reference\n            };\n        },\n        mounted() {\n            // Listen for incoming messages to populate topologies\n            this.$watch('msg.payload', (newPayload) => {\n                if (Array.isArray(newPayload)) {\n                    this.topologies = newPayload;\n                    console.log(\"Topologies updated:\", this.topologies);\n                }\n            });\n        },\n        watch: {\n            selectedTopology(newTopologyName) {\n                const selectedTopology = this.topologies.find(\n                    topology => topology.name === newTopologyName\n                );\n\n                if (selectedTopology) {\n                    this.changeTopology(selectedTopology.data);\n                }\n            },\n        },\n        methods: {\n            initializeTopology(topologyData) {\n                console.log(\"Initializing topology:\", topologyData);\n\n                // Instantiate nx Application\n                const app = new nx.ui.Application();\n\n                // Configuration for topology\n                const topologyConfig = {\n                    width: window.innerWidth,\n                    height: window.innerHeight,\n                    nodeConfig: {\n                        label: \"model.name\",\n                        iconType: \"model.device_type\",\n                        color: \"model.color\",\n                    },\n                    linkConfig: {\n                        linkType: \"straight\",\n                        color: \"model.color\",\n                    },\n                    showIcon: true,\n                };\n\n                // Instantiate Topology\n                const topology = new nx.graphic.Topology(topologyConfig);\n                topology.data(topologyData);\n                topology.attach(app);\n\n                // Attach the app to the container\n                app.container(document.getElementById(\"topology-container\"));\n\n                // Save the app reference\n                this.topologyApp = app;\n            },\n            changeTopology(topologyData) {\n                console.log(\"Changing topology to:\", topologyData);\n\n                if (!topologyData) return;\n\n                // Clean up existing topology\n                if (this.topologyApp) {\n                    console.log(\"Destroying existing topology...\");\n                    this.topologyApp.destroy();\n                    this.topologyApp = null;\n\n                    // Clear the container\n                    const container = document.getElementById(\"topology-container\");\n                    container.innerHTML = '';\n                }\n\n                // Initialize new topology\n                this.initializeTopology(topologyData);\n            },\n        },\n        unmounted() {\n            if (this.topologyApp) {\n                this.topologyApp.destroy();\n            }\n        },\n    };\n</script>\n\n<style>\n  #topology-container {\n    width: 100%;\n    height: 100%;\n    background-color: #f0f0f0;\n    overflow: hidden;\n  }\n\n  body {\n    background-color: white;\n  }\n</style>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "widget:page",
        "className": "nextjs",
        "x": 480,
        "y": 380,
        "wires": [
            [
                "7fd6679aaeecfae0"
            ]
        ]
    },
    {
        "id": "af4f186e266efab5",
        "type": "ui-page",
        "name": "topo",
        "ui": "64fc71361e24a0d0",
        "path": "/page4",
        "icon": "home",
        "layout": "grid",
        "theme": "",
        "breakpoints": [
            {
                "name": "Default",
                "px": "0",
                "cols": "3"
            },
            {
                "name": "Tablet",
                "px": "576",
                "cols": "6"
            },
            {
                "name": "Small Desktop",
                "px": "768",
                "cols": "9"
            },
            {
                "name": "Desktop",
                "px": "1024",
                "cols": "12"
            }
        ],
        "order": 5,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "64fc71361e24a0d0",
        "type": "ui-base",
        "name": "",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-iframe",
            "ui-control",
            "ui-template",
            "ui-gauge",
            "ui-chart",
            "ui-slider",
            "ui-form",
            "ui-text-input",
            "ui-number-input",
            "ui-file-input",
            "ui-button",
            "ui-button-group",
            "ui-dropdown",
            "ui-radio-group",
            "ui-switch",
            "ui-text",
            "ui-chart",
            "ui-form",
            "ui-number-input",
            "ui-switch",
            "ui-table",
            "ui-gauge",
            "ui-markdown",
            "ui-iframe",
            "ui-tabulator",
            "ui-radio-group",
            "ui-dropdown",
            "ui-button-group",
            "ui-file-input"
        ],
        "showPathInSidebar": false,
        "showPageTitle": false,
        "navigationStyle": "icon",
        "titleBarStyle": "fixed"
    }
]

this is my dropdown while injecting the node only the dropdown item showing.otherwise it wont.

The problem:

When I trigger the flow using the Inject node, the dropdown for topologies appears, and everything works fine. However, I want to trigger the flow automatically without needing to use the Inject node.

How can I run this flow without using the Inject node? Can I trigger it programmatically or automatically upon page load?

Have a look at the ui-event node.

1 Like

Thanks colin . It is working thankyou for giving me a suggestion.

I’m working on a Node-RED project using the dashboard module and have a requirement where I want the ui-event node to trigger events for specific pages in the UI.

Currently, the default behavior is to trigger events only under the /dashboard path. However, I would like to have it trigger events for specific pages, such as /dashboard/page1 or /dashboard/page2.

For example:

  • Instead of catching all events under /dashboard, I want to specifically target /dashboard/page1 for some logic.

Is there a way to achieve this functionality with the existing ui-event node? Or are there any alternative methods or configurations I can use to accomplish this?

Use a debug node (set to display full msg) and see what happens - then use a switch node to only permit messages that meet your criteria to pass through.

can you give the structure of the nodes what you are conveying so that it may be helpful me to understand.

I cannot. I am away from computers for next few days. However, what I suggested is very straight forward and requires very basic node-red skills. Perhaps you would benefit from a little time learning?

I recommend watching this playlist: Node-RED Essentials. The videos are done by the developers of node-red. They're nice & short and to the point. You will understand a whole lot more in about 1 hour. A small investment for a lot of gain.

[
{
"id": "b9b7b3331331a6d2",
"type": "ui-event",
"z": "de4745db77ed435c",
"ui": "64fc71361e24a0d0",
"name": "",
"x": 70,
"y": 520,
"wires": [
[
"f53e204c66caeedd"
]
]
},
{
"id": "a2b62a9577fa2ff3",
"type": "debug",
"z": "de4745db77ed435c",
"name": "debug 2586",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 350,
"y": 580,
"wires":
},
{
"id": "f53e204c66caeedd",
"type": "switch",
"z": "de4745db77ed435c",
"name": "",
"property": "payload.path",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "/dashboard/page4",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 190,
"y": 520,
"wires": [
[
"d86274362a31afef"
]
]
},
{
"id": "d86274362a31afef",
"type": "function",
"z": "de4745db77ed435c",
"name": "function 15",
"func": "node.log("----------------->Path: " + msg.payload.path);\nreturn msg;\n\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": ,
"x": 330,
"y": 520,
"wires": [
[
"a2b62a9577fa2ff3"
]
]
},
{
"id": "64fc71361e24a0d0",
"type": "ui-base",
"name": "",
"path": "/dashboard",
"appIcon": "",
"includeClientData": true,
"acceptsClientConfig": [
"ui-iframe",
"ui-control",
"ui-template",
"ui-gauge",
"ui-chart",
"ui-slider",
"ui-form",
"ui-text-input",
"ui-number-input",
"ui-file-input",
"ui-button",
"ui-button-group",
"ui-dropdown",
"ui-radio-group",
"ui-switch",
"ui-text",
"ui-chart",
"ui-form",
"ui-number-input",
"ui-switch",
"ui-table",
"ui-gauge",
"ui-markdown",
"ui-iframe",
"ui-tabulator",
"ui-radio-group",
"ui-dropdown",
"ui-button-group",
"ui-file-input"
],
"showPathInSidebar": false,
"showPageTitle": false,
"navigationStyle": "icon",
"titleBarStyle": "fixed"
}
]

using the switch node also .still i m not even get the message in the debug node.can you give only for that page only the function could trigger any suggestions.

I'm not going to load all that code, indeed I can't because you didn't post it between two lines each containing three back ticks such as the </> button provides
image

However what @Steve-Mcl suggests is that you put a debug node after the ui-event node
image
Then visit the dashboard pages and explore the differences in the debug output.

Pay particular attention to the value of msg.payload.page.path.
Perhaps you could use this in a switch node?

yes .thanks now i understand how can we have to give for the particular page. instead of page i used path. so that i could not get the way for that output. thank you for the suggestion.