Skip to content
Julian Knight edited this page Nov 25, 2019 · 13 revisions

UPDATE 2019-09-02: Updated for uibuilder v2. UPDATE 2019-11-25: Updated css link tags to prevent Refused to apply style errors.

This is an example of using uibuilder with just JQuery. JQuery is included in the node installation by default.

This example is included in the uibuilder installation. Import it from the examples.

For simple use, JQuery can be adequate to enable you to dynamically update the UI as messages come into the node and across to the front end over Socket.IO. For more advanced use, consider using a front-end library such as the default VueJS.

Note that I will assume your userDir is at ~/.node-red which is the default.

Installation

For easy installation, use the import menu, and choose the jquery entry from the uibuilder examples. Then amend the index.(html|js|css) files from the text contained in the comment nodes.

To manually install:

  1. Install uibuilder using Node-RED's palette manager
  2. Add a uibuilder node and deploy
  3. Amend the template files index.(html|js|css) according to the examples given here
  4. Add input and output nodes & re-deploy
  5. Open the jq URL In your favourite browser. If you are using default settings and running Node-RED on the same machine as the browser, this will be http://localhost:1880/jq.

The JQuery example doesn't currently have a button to send a message back to Node-RED but you can open your browser's developer console and type in something like:

uibuilder.send( {payload: 'What a breeze!'} )

The msg should then appear in the debug window of Node-RED.

Screenshots

Example Flow

Import this to Node-RED and deploy.

[
    {
        "id": "a8ef56e9.e61a98",
        "type": "debug",
        "z": "63281c77.40a064",
        "name": "jquery-debug",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 650,
        "y": 2080,
        "wires": []
    },
    {
        "id": "2eb501ec.6cb09e",
        "type": "uibuilder",
        "z": "63281c77.40a064",
        "name": "jQuery Example",
        "topic": "",
        "url": "jq",
        "fwdInMessages": false,
        "allowScripts": false,
        "allowStyles": false,
        "copyIndex": true,
        "showfolder": false,
        "x": 460,
        "y": 2100,
        "wires": [
            [
                "a8ef56e9.e61a98"
            ],
            [
                "54132099.1a374"
            ]
        ]
    },
    {
        "id": "8f8cb1e.3cc5a5",
        "type": "inject",
        "z": "63281c77.40a064",
        "name": "",
        "topic": "uibuilder-jquery",
        "payload": "{\"lib\":\"jquery\", \"testNum\": 500}",
        "payloadType": "json",
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "x": 320,
        "y": 2100,
        "wires": [
            [
                "2eb501ec.6cb09e"
            ]
        ]
    },
    {
        "id": "54132099.1a374",
        "type": "debug",
        "z": "63281c77.40a064",
        "name": "uib controls",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 650,
        "y": 2120,
        "wires": []
    },
    {
        "id": "f08129f6.4ada58",
        "type": "comment",
        "z": "63281c77.40a064",
        "name": "uibuilder/jQuery Example",
        "info": "[Front-End](/jq)\n\n## Configuration\n\nInstall jQuery via the nodes configuration panel.\n\nThen update the files:\n\n* `index.html`\n* `index.js`\n* `index.css`\n\nAccording to the jQuery example(s) in the \n[WIKI](https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Example:-JQuery)\nwhich are also included in the 3 other comment nodes in this example.",
        "x": 310,
        "y": 2040,
        "wires": []
    },
    {
        "id": "c30edc95.8f826",
        "type": "comment",
        "z": "63281c77.40a064",
        "name": "index.html",
        "info": "<!doctype html>\n<html lang=\"en\"><head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes\">\n\n    <title>uibuilder jQuery example</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Example using jQuery\">\n\n    <link rel=\"icon\" href=\"./images/node-blue.ico\">\n\n    <!-- OPTIONAL: Normalize is used to make things the same across browsers. Index is for your styles -->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"../uibuilder/vendor/normalize.css/normalize.css\">\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n</head><body>\n    <!-- The \"app\" element is where the code for dynamic updates is attached -->\n    <div id=\"app\">\n        <h1>\n            Welcome to UIbuilder for Node-RED\n        </h1>\n        <p>\n            This is an example of using uibuilder with jQuery. If you open the developer console, you will see some debug output.\n            You can also see some dynamic data updating below, thanks to JQuery.\n            Additional information may be available in the\n            <a href=\"https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Example:-JQuery\">WIKI</a>\n        </p>\n        <p>\n            Please see the README for the\n            <a href=\"https://github.com/TotallyInformation/node-red-contrib-uibuilder\">node-red-contrib-uibuilder</a>\n            node for details on how to use uibuilder.\n        </p>\n        <h2>Dynamic Data (via JQuery)</h2>\n        <p>UIBuilder Front-End Version: <span id=\"feVersion\"></span></p>\n        <p>Websocket State: <span id=\"socketConnectedState\"></span></p>\n        <p>Messages Received: <span id=\"msgsReceived\"></span></p>\n        <p>Control Messages Received: <span id=\"msgsControl\"></span></p>\n        <p>Messages Sent: <span id=\"msgsSent\"></span></p>\n        <p>Last Message Received:</p>\n        <code id=\"showMsg\"></code>\n        <p>Last Control Message Received:</p>\n        <code id=\"showCtrlMsg\"></code>\n        <p>Last Message Sent:</p>\n        <code id=\"showMsgSent\"></code>\n    </div>\n    <!-- These MUST be in the right order. Note no leading / -->\n    <!-- REQUIRED: Socket.IO is loaded only once for all instances\n                     Without this, you don't get a websocket connection -->\n    <script src=\"../uibuilder/vendor/socket.io/socket.io.js\"></script>\n\n    <!-- --- Vendor Libraries - Load in the right order --- -->\n    <script src=\"../uibuilder/vendor/jquery/dist/jquery.min.js\"></script>\n\n    <!-- REQUIRED: Sets up Socket listeners and the msg object -->\n    <!-- <script src=\"./uibuilderfe.js\"></script>   //dev version -->\n    <script src=\"./uibuilderfe.min.js\"></script> <!--    //prod version -->\n    <!-- OPTIONAL: Put your custom code in here -->\n    <script src=\"./index.js\"></script>\n\n</body></html>\n",
        "x": 500,
        "y": 2040,
        "wires": [],
        "icon": "node-red/parser-html.svg"
    },
    {
        "id": "8bd07771.336748",
        "type": "comment",
        "z": "63281c77.40a064",
        "name": "index.js",
        "info": "/* jshint browser: true, esversion: 5, asi: true */\n/*globals $, uibuilder */\n// @ts-nocheck\n/*\n  Copyright (c) 2019 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n'use strict'\n\n/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */\n\n// When JQuery is ready, update\n$( document ).ready(function() {\n    /** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3\n     * Pass the namespace and ioPath variables if hosting page is not in the instance root folder\n     * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.\n     * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names\n     */\n    uibuilder.start()\n\n    // Initial set\n    $('#msgsReceived').text( uibuilder.get('msgsReceived') )\n    $('#msgsControl').text( uibuilder.get('msgsCtrl') )\n    $('#msgsSent').text( uibuilder.get('msgsSent') )\n    $('#socketConnectedState').text( uibuilder.get('ioConnected') )\n    $('#feVersion').text( uibuilder.get('version') )\n\n    // Turn on debugging (default is off)\n    //uibuilder.debug(true)\n\n    // If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO\n    // Note that you can also listen for 'msgsReceived' as they are updated at the same time\n    // but newVal relates to the attribute being listened to.\n    uibuilder.onChange('msg', function(newVal){\n        console.info('property msg changed!')\n        console.dir(newVal)\n        $('#showMsg').text(JSON.stringify(newVal))\n        //uibuilder.set('msgCopy', newVal)\n    })\n\n    // You can get attributes manually. Non-existent attributes return 'undefined'\n    //console.dir(uibuilder.get('msg'))\n\n    // You can also set things manually. See the list of attributes top of page.\n    // You can add arbitrary attributes to the object, you cannot overwrite internal attributes\n\n    // Try setting a restricted, internal attribute - see the warning in the browser console\n    uibuilder.set('msg', 'You tried but failed!')\n\n    // Remember that onChange functions don't trigger if you haven't set them\n    // up BEFORE an attribute change.\n    uibuilder.onChange('msgCopy', function(newVal){\n        console.info('msgCopy changed. New value: ', newVal)\n    })\n\n    // Now try setting a new attribute - this will be an empty object because\n    // msg won't yet have been received\n    uibuilder.set('msgCopy', uibuilder.msg)\n    // Hint: Try putting this set into the onChange for 'msg'\n\n    // As noted, we could get the msg here too\n    uibuilder.onChange('msgsReceived', function(newVal){\n        console.info('New msg sent to us from Node-RED over Socket.IO. Total Count: ', newVal)\n        $('#msgsReceived').text(newVal)\n        // uibuilder.msg is a shortcut for uibuilder.get('msg')\n        //$('#showMsg').text(JSON.stringify(uibuilder.msg))\n    })\n\n    // If Socket.IO connects/disconnects\n    uibuilder.onChange('ioConnected', function(newVal){\n        console.info('Socket.IO Connection Status Changed: ', newVal)\n        $('#socketConnectedState').text(newVal)\n    })\n\n    // If a message is sent back to Node-RED\n    uibuilder.onChange('msgsSent', function(newVal){\n        console.info('New msg sent to Node-RED over Socket.IO. Total Count: ', newVal)\n        $('#msgsSent').text(newVal)\n        $('#showMsgSent').text(JSON.stringify(uibuilder.get('sentMsg')))\n    })\n\n    // If we receive a control message from Node-RED\n    uibuilder.onChange('msgsCtrl', function(newVal){\n        console.info('New control msg sent to us from Node-RED over Socket.IO. Total Count: ', newVal)\n        $('#msgsControl').text(newVal)\n        $('#showCtrlMsg').text(JSON.stringify(uibuilder.get('ctrlMsg')))\n    })\n\n    //Manually send a message back to Node-RED after 2 seconds\n    window.setTimeout(function(){\n        console.info('Sending a message back to Node-RED - after 2s delay')\n        uibuilder.send( { 'topic':'uibuilderfe', 'payload':'I am a message sent from the uibuilder front end' } )\n    }, 2000)\n\n}) // --- End of JQuery Ready --- //\n\n// EOF\n",
        "x": 630,
        "y": 2040,
        "wires": [],
        "icon": "font-awesome/fa-code"
    },
    {
        "id": "9b587d6d.a6fb",
        "type": "comment",
        "z": "63281c77.40a064",
        "name": "index.css",
        "info": "body {font-family: sans-serif;}\ndiv, p, code { margin:0.3em; padding: 0.3em;}",
        "x": 760,
        "y": 2040,
        "wires": [],
        "icon": "node-red/hash.svg"
    }
]

Example front-end files

index.html

<!doctype html>
<html lang="en"><head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

    <title>uibuilder jQuery example</title>
    <meta name="description" content="Node-RED uibuilder - Example using jQuery">

    <link rel="icon" href="./images/node-blue.ico">

    <!-- OPTIONAL: Normalize is used to make things the same across browsers. Index is for your styles -->
    <link type="text/css" rel="stylesheet" href="../uibuilder/vendor/normalize.css/normalize.css">
    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

</head><body>
    <!-- The "app" element is where the code for dynamic updates is attached -->
    <div id="app">
        <h1>
            Welcome to UIbuilder for Node-RED
        </h1>
        <p>
            This is an example of using uibuilder with jQuery. If you open the developer console, you will see some debug output.
            You can also see some dynamic data updating below, thanks to JQuery.
            Additional information may be available in the
            <a href="https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Example:-JQuery">WIKI</a>
        </p>
        <p>
            Please see the README for the
            <a href="https://github.com/TotallyInformation/node-red-contrib-uibuilder">node-red-contrib-uibuilder</a>
            node for details on how to use uibuilder.
        </p>
        <h2>Dynamic Data (via JQuery)</h2>
        <p>UIBuilder Front-End Version: <span id="feVersion"></span></p>
        <p>Websocket State: <span id="socketConnectedState"></span></p>
        <p>Messages Received: <span id="msgsReceived"></span></p>
        <p>Control Messages Received: <span id="msgsControl"></span></p>
        <p>Messages Sent: <span id="msgsSent"></span></p>
        <p>Last Message Received:</p>
        <code id="showMsg"></code>
        <p>Last Control Message Received:</p>
        <code id="showCtrlMsg"></code>
        <p>Last Message Sent:</p>
        <code id="showMsgSent"></code>
    </div>
    <!-- These MUST be in the right order. Note no leading / -->
    <!-- REQUIRED: Socket.IO is loaded only once for all instances
                     Without this, you don't get a websocket connection -->
    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>

    <!-- --- Vendor Libraries - Load in the right order --- -->
    <script src="../uibuilder/vendor/jquery/dist/jquery.min.js"></script>

    <!-- REQUIRED: Sets up Socket listeners and the msg object -->
    <!-- <script src="./uibuilderfe.js"></script>   //dev version -->
    <script src="./uibuilderfe.min.js"></script> <!--    //prod version -->
    <!-- OPTIONAL: Put your custom code in here -->
    <script src="./index.js"></script>

</body></html>

Note that you can use uibuilderfe.js if you want to be able to debug my front-end library more easily.

index.css

body {font-family: sans-serif;}
div, p, code { margin:0.3em; padding: 0.3em;}

index.js

/* jshint browser: true, esversion: 5, asi: true */
/*globals $, uibuilder */
// @ts-nocheck
/*
  Copyright (c) 2019 Julian Knight (Totally Information)

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/
'use strict'

/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */

// When JQuery is ready, update
$( document ).ready(function() {
    /** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3
     * Pass the namespace and ioPath variables if hosting page is not in the instance root folder
     * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.
     * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names
     */
    uibuilder.start()

    // Initial set
    $('#msgsReceived').text( uibuilder.get('msgsReceived') )
    $('#msgsControl').text( uibuilder.get('msgsCtrl') )
    $('#msgsSent').text( uibuilder.get('msgsSent') )
    $('#socketConnectedState').text( uibuilder.get('ioConnected') )
    $('#feVersion').text( uibuilder.get('version') )

    // Turn on debugging (default is off)
    //uibuilder.debug(true)

    // If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
    // Note that you can also listen for 'msgsReceived' as they are updated at the same time
    // but newVal relates to the attribute being listened to.
    uibuilder.onChange('msg', function(newVal){
        console.info('property msg changed!')
        console.dir(newVal)
        $('#showMsg').text(JSON.stringify(newVal))
        //uibuilder.set('msgCopy', newVal)
    })

    // You can get attributes manually. Non-existent attributes return 'undefined'
    //console.dir(uibuilder.get('msg'))

    // You can also set things manually. See the list of attributes top of page.
    // You can add arbitrary attributes to the object, you cannot overwrite internal attributes

    // Try setting a restricted, internal attribute - see the warning in the browser console
    uibuilder.set('msg', 'You tried but failed!')

    // Remember that onChange functions don't trigger if you haven't set them
    // up BEFORE an attribute change.
    uibuilder.onChange('msgCopy', function(newVal){
        console.info('msgCopy changed. New value: ', newVal)
    })

    // Now try setting a new attribute - this will be an empty object because
    // msg won't yet have been received
    uibuilder.set('msgCopy', uibuilder.msg)
    // Hint: Try putting this set into the onChange for 'msg'

    // As noted, we could get the msg here too
    uibuilder.onChange('msgsReceived', function(newVal){
        console.info('New msg sent to us from Node-RED over Socket.IO. Total Count: ', newVal)
        $('#msgsReceived').text(newVal)
        // uibuilder.msg is a shortcut for uibuilder.get('msg')
        //$('#showMsg').text(JSON.stringify(uibuilder.msg))
    })

    // If Socket.IO connects/disconnects
    uibuilder.onChange('ioConnected', function(newVal){
        console.info('Socket.IO Connection Status Changed: ', newVal)
        $('#socketConnectedState').text(newVal)
    })

    // If a message is sent back to Node-RED
    uibuilder.onChange('msgsSent', function(newVal){
        console.info('New msg sent to Node-RED over Socket.IO. Total Count: ', newVal)
        $('#msgsSent').text(newVal)
        $('#showMsgSent').text(JSON.stringify(uibuilder.get('sentMsg')))
    })

    // If we receive a control message from Node-RED
    uibuilder.onChange('msgsCtrl', function(newVal){
        console.info('New control msg sent to us from Node-RED over Socket.IO. Total Count: ', newVal)
        $('#msgsControl').text(newVal)
        $('#showCtrlMsg').text(JSON.stringify(uibuilder.get('ctrlMsg')))
    })

    //Manually send a message back to Node-RED after 2 seconds
    window.setTimeout(function(){
        console.info('Sending a message back to Node-RED - after 2s delay')
        uibuilder.send( { 'topic':'uibuilderfe', 'payload':'I am a message sent from the uibuilder front end' } )
    }, 2000)

}) // --- End of JQuery Ready --- //

// EOF

uibuilderfe.js

This is the magic that allows you to have a much simplified index.js. It does all the heavy lifting with Socket.IO and gives you an onChange function to listen for changes to key variables so that you can update the UI.

Normally, you wouldn't have this file in your local src folder, it would be picked up from the master folder. If you want to see what it does, please use the version in the repo.

Clone this wiki locally