Example of using a web front end login modal form
This flow demonstrates how to create a simple web login front-end with Node-RED that allows users to log in with their credentials.
After you have deployed this flow you can then access the login.
To access the login page, enter the URL of your Node-RED instance followed by /login in your browser's address bar.
Upon hitting a button to ask for the login, the user is then presented with a fade in input modal.
The flow consists of the following nodes:
An http in node that listens for GET requests at the /login URL and passes the message to a function node.
A function node that sets the msg.url property to /loginpost and the HTTP method to POST. It then passes the message to two template nodes, one for the CSS and one for the HTML the login will use.
Next is the HTTP in node that is listening to POST methods with the URI of /loginpost.
Then a JSON node converts the payload to a JSON string, for demo purposes and passes the message a function node to format a message to send to the HTTP Response node.
Additionally, a debug node that sends the message object to the debug window from the loginpost node.
For the IBM i lovers, this example will run on the IBM i without any issues.
This flow was inspired by the tutorials and examples from w3schools.com.
[{"id":"11d683029368b71c","type":"tab","label":"Login Form","disabled":false,"info":"","env":[]},{"id":"ca9b95ca516317af","type":"group","z":"11d683029368b71c","g":"e163ddcb6cbd5caa","name":"Login Form","style":{"label":true},"nodes":["5660b46ab5b6d219","8ce444acfc6de336","b27ef0ad79b174d6","be8c2fce8df81cb7","30c7e238d93da638"],"x":134,"y":319,"w":1032,"h":82},{"id":"8b6e4bd9546e18c4","type":"group","z":"11d683029368b71c","g":"e163ddcb6cbd5caa","name":"Login Submitted Form","style":{"label":true},"nodes":["4b7e90029e558631","193e2c791d447cd6","99237e2d82c201ba","4043d74cfe623c83","7b2b7f0ff09ea904"],"x":134,"y":479,"w":812,"h":142},{"id":"e163ddcb6cbd5caa","type":"group","z":"11d683029368b71c","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["ca9b95ca516317af","8b6e4bd9546e18c4"],"x":108,"y":293,"w":1084,"h":354},{"id":"5660b46ab5b6d219","type":"http in","z":"11d683029368b71c","g":"ca9b95ca516317af","name":"","url":"/login","method":"get","upload":false,"swaggerDoc":"","x":220,"y":360,"wires":[["8ce444acfc6de336"]]},{"id":"8ce444acfc6de336","type":"function","z":"11d683029368b71c","g":"ca9b95ca516317af","name":"set url = \"loginpost\";","func":"msg.url = \"loginpost\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":444,"y":360,"wires":[["b27ef0ad79b174d6"]]},{"id":"b27ef0ad79b174d6","type":"template","z":"11d683029368b71c","g":"ca9b95ca516317af","name":"CSS","field":"payload.style","fieldType":"msg","format":"html","syntax":"mustache","template":"body {font-family: Arial, Helvetica, sans-serif;}\n\n/* Full-width input fields */\ninput[type=text], input[type=password] {\nwidth: 100%;\npadding: 12px 20px;\nmargin: 8px 0;\ndisplay: inline-block;\nborder: 1px solid #ccc;\nbox-sizing: border-box;\n}\n\n/* Set a style for all buttons */\nbutton {\nbackground-color: #04AA6D;\ncolor: white;\npadding: 14px 20px;\nmargin: 8px 0;\nborder: none;\ncursor: pointer;\nwidth: 100%;\n}\n\nbutton:hover {\nopacity: 0.8;\n}\n\n/* Extra styles for the cancel button */\n.cancelbtn {\nwidth: auto;\npadding: 10px 18px;\nbackground-color: #f44336;\nborder-radius: 10%;\n}\n\n/* Center the image and position the close button */\n.imgcontainer {\ntext-align: center;\nmargin: 24px 0 12px 0;\nposition: relative;\n}\n\nimg.avatar {\nwidth: 40%;\nborder-radius: 5%;\n}\n\n.container {\npadding: 16px;\n}\n\nspan.psw {\nfloat: right;\npadding-top: 16px;\n}\n\n/* The Modal (background) */\n.modal {\ndisplay: none; /* Hidden by default */\nposition: fixed; /* Stay in place */\nz-index: 1; /* Sit on top */\nleft: 0;\ntop: 0;\nwidth: 100%; /* Full width */\nheight: 100%; /* Full height */\noverflow: auto; /* Enable scroll if needed */\nbackground-color: rgb(0,0,0); /* Fallback color */\nbackground-color: rgba(0,0,0,0.4); /* Black w/ opacity */\npadding-top: 60px;\n}\n\n/* Modal Content/Box */\n.modal-content {\nbackground-color: #fefefe;\nmargin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */\nborder: 1px solid #888;\nwidth: 80%; /* Could be more or less, depending on screen size */\n}\n\n/* The Close Button (x) */\n.close {\nposition: absolute;\nright: 25px;\ntop: 0;\ncolor: #000;\nfont-size: 35px;\nfont-weight: bold;\n}\n\n.close:hover,\n.close:focus {\ncolor: red;\ncursor: pointer;\n}\n\n/* Add Zoom Animation */\n.animate {\n-webkit-animation: animatezoom 0.6s;\nanimation: animatezoom 0.6s\n}\n\n@-webkit-keyframes animatezoom {\nfrom {-webkit-transform: scale(0)}\nto {-webkit-transform: scale(1)}\n}\n\n@keyframes animatezoom {\nfrom {transform: scale(0)}\nto {transform: scale(1)}\n}\n\n/* Change styles for span and cancel button on extra small screens */\n@media screen and (max-width: 300px) {\nspan.psw {\ndisplay: block;\nfloat: none;\n}\n.cancelbtn {\nwidth: 100%;\n}\n}","x":690,"y":360,"wires":[["30c7e238d93da638"]]},{"id":"be8c2fce8df81cb7","type":"http response","z":"11d683029368b71c","g":"ca9b95ca516317af","name":"HTTP Response","statusCode":"","headers":{},"x":1060,"y":360,"wires":[]},{"id":"30c7e238d93da638","type":"template","z":"11d683029368b71c","g":"ca9b95ca516317af","name":"HTML","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n\n<head>\n <!-- Required meta tags -->\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n <meta name=\"description\" content=\"We are experts in everything related to IBM i.\">\n <meta name=\"keywords\" content=\"IBM i, FormaServe, Training, RPG, SQL, PHP, NodeJS, AS400, iSeries, Open-Source Node.js PHP Node-RED\">\n <meta name=\"author\" content=\"FormaServe Systems Ltd\">\n\n <title>FormaServe</title>\n \n<style>{{{payload.style}}}</style>\n</head>\n\n<body>\n<div class=\"container\">\n<br>\n<h2>Login Form</h2>\n\n<button onclick=\"document.getElementById('id01').style.display='block'\" style=\"width:auto;\">Click to Login</button>\n</div>\n\n<div id=\"id01\" class=\"modal\">\n \n <form class=\"modal-content animate\" action=\"/loginpost\" method=\"post\">\n \n <div class=\"imgcontainer\">\n <span onclick=\"document.getElementById('id01').style.display='none'\" class=\"close\" title=\"Close Modal\">×</span>\n <img src=\"https://www.formaserve.co.uk/_graphics/logo_1.png\" alt=\"fss-logo\" class=\"avatar\">\n </div>\n\n <div class=\"container\">\n <label for=\"uname\"><b>Username</b></label>\n <input type=\"text\" placeholder=\"Enter Username\" name=\"uname\" required>\n\n <label for=\"psw\"><b>Password</b></label>\n <input type=\"password\" placeholder=\"Enter Password\" name=\"psw\" required>\n \n <button type=\"submit\">Login</button>\n <label>\n <input type=\"checkbox\" checked=\"checked\" name=\"remember\"> Remember me\n </label>\n </div>\n\n <div class=\"container\" style=\"background-color:#f1f1f1\">\n <button type=\"button\" onclick=\"document.getElementById('id01').style.display='none'\" class=\"cancelbtn\">Cancel</button>\n <span class=\"psw\">Forgot <a href=\"#\">password?</a></span>\n </div>\n </form>\n</div>\n\n<script>\n// Get the modal\nvar modal = document.getElementById('id01');\n\n// When the user clicks anywhere outside of the modal, close it\nwindow.onclick = function(event) {\n if (event.target == modal) {\n modal.style.display = \"none\";\n }\n}\n</script>\n\n</body>\n</html>\n","x":870,"y":360,"wires":[["be8c2fce8df81cb7"]]},{"id":"4b7e90029e558631","type":"http in","z":"11d683029368b71c","g":"8b6e4bd9546e18c4","name":"","url":"/loginpost","method":"post","upload":false,"swaggerDoc":"","x":240,"y":520,"wires":[["193e2c791d447cd6","7b2b7f0ff09ea904"]]},{"id":"193e2c791d447cd6","type":"debug","z":"11d683029368b71c","g":"8b6e4bd9546e18c4","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":395,"y":580,"wires":[],"l":false},{"id":"99237e2d82c201ba","type":"http response","z":"11d683029368b71c","g":"8b6e4bd9546e18c4","name":"","statusCode":"","headers":{},"x":870,"y":520,"wires":[]},{"id":"4043d74cfe623c83","type":"function","z":"11d683029368b71c","g":"8b6e4bd9546e18c4","name":"build payload to client","func":"msg.payload = `The msg.payload contains: ${msg.payload}` \n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":520,"wires":[["99237e2d82c201ba"]]},{"id":"7b2b7f0ff09ea904","type":"json","z":"11d683029368b71c","g":"8b6e4bd9546e18c4","name":"Convert Post","property":"payload","action":"","pretty":false,"x":443.33333333333326,"y":520,"wires":[["4043d74cfe623c83"]]}]