Front-end Website with Node-RED: Example Form

This Flow demonstrates how to create a simple front-end webpage with Node-RED.

The public facing page consists of the client side JavaScript, CSS and HTML.

The important technique is how the mustache templates are used. Each template will set the "property" relative to the content.

The CSS node sets the "msg.payload.style" property. The JavaScript node sets the "msg.payload.script" property. The HTML node then includes these properties

<script>{{{payload.script}}}</script>
<style>{{{payload.style}}}</style>

This example was created by http://www.InternetofLEGO.com

alt tag alt tag

\n \n \n \n\n

Using CSS to style an HTML form with AJAX POST and Node-RED

\n

Internet of LEGO

\n\n
\n
\n \n \n\n \n \n\n \n \n \n \n
\n
\n
\n \n
\n\n\n\n","x":690,"y":340,"wires":[["d2c0bc2a.05a02"]]},{"id":"57316751.8bd948","type":"comment","z":"6af27206.74dccc","name":"Login Form","info":"","x":350,"y":300,"wires":[]},{"id":"ad88b28c.bc842","type":"function","z":"6af27206.74dccc","name":"return msg.payload to client","func":"msg.payload = 'The following data was submitted and available in the msg.payload: '+msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":400,"wires":[["8de9647.b8a9a98"]]},{"id":"42a9d329.9cdf6c","type":"comment","z":"6af27206.74dccc","name":"Inject msg object properties","info":"","x":360,"y":200,"wires":[]},{"id":"75913f37.78e6e","type":"json","z":"6af27206.74dccc","name":"","x":370,"y":400,"wires":[["ad88b28c.bc842"]]},{"id":"86c08a83.385758","type":"comment","z":"6af27206.74dccc","name":"Website","info":"","x":130,"y":160,"wires":[]},{"id":"111485fa.14c4aa","type":"comment","z":"6af27206.74dccc","name":"Form Submission","info":"","x":160,"y":380,"wires":[]},{"id":"3c029955.901626","type":"comment","z":"6af27206.74dccc","name":"Node-RED Public Site - README","info":"This Flow demonstrates how to create\na simple frontend webpage with Node-RED.\n\nThe public facing page consists of the \nclient side JavaScript, CSS and HTML. \n\nThe important technique is how the mustache \ntemplates are used. Each template will set the\n\"property\" relative to the content. \n\nThe CSS node sets the \"msg.payload.style\" property.\nThe JavaScript node sets the \"msg.payload.script\" property.\nThe HTML node then includes these properties \n\n\n\n\nThis example was created by http://www.InternetofLEGO.com\n\n","x":460,"y":60,"wires":[]}] /** * Parse the flow.json to get the details on the tabs/subflows present */ const processFlow = function (flow) { const tabids = [] const tabs = [] flow.forEach((d) => { if (d.type === 'subflow') { tabids.push(d.id) tabs.push({ id: d.id, label: d.name, type: 'subslow' }) } else if (d.z) { if (tabids.indexOf(d.z) === -1) { tabids.push(d.z) tabs.push({ id: d.z, label: d.z, type: 'tab', }) } } }) return tabs } function addPanZoom () { var svgs = d3.selectAll('.flowviewer svg'); svgs.each(function() { var svg = d3.select(this); svg.html('' + svg.html() + ''); var inner = svg.select('g'); var zoom = d3.zoom() .translateExtent([[0, 0], [3000, 3000]]) .scaleExtent([0.5, 1]) .on("start", function () { svg.classed("dragging", true); }) .on('zoom', function(event) { inner.attr('transform', event.transform); }) .on("end", function () { svg.classed("dragging", false); }); svg.call(zoom); }); } const clearFlow = function () { $('.flowviewer svg .flowGridlines').empty() $('.flowviewer svg .containerGroup').empty() $('.flowviewer svg .flowGroups').empty() $('.flowviewer svg .flowWires').empty() $('.flowviewer svg .flowNodes').empty() } // get the tabs/subflows for our provided flow const tabs = processFlow(flow) // sort them such that tabs render first tabs.sort((a, b) => { return a.type > b.type ? -1 : (a.type < b.type) ? 1 : 0 }) function openTab (id) { // clear any existing flow clearFlow() // draw the new flow - uses function from `public/js/flowviewer.js` renderFlow(id, flow, $('.flowviewer svg')); addPanZoom() } function addTab (tab, index) { const classes = 'flowviewer-tab flowviewer-' + tab.type const name = tab.type === 'tab' ? 'Flow ' + (index + 1) : tab.label const tabDOM = $('.flowviewer-tabs') .append(`
${name}
`) .on('click', `#flowviewer-tab-${index}`, function () { // add on click to each new tab $('.flowviewer-tab').removeClass('active') $(this).addClass('active') openTab(tab.id) }) } tabs.forEach((tab, index) => { addTab(tab, index) }) clearFlow(); renderFlow(tabs[0].id, flow, $('.flowviewer svg')); addPanZoom(); $('#flowviewer-tab-0').addClass('active') $('#copy-flow').on('click', function() { navigator.clipboard.writeText(JSON.stringify(flow)); }) })()
[{"id":"1e0841f1.ac68fe","type":"http in","z":"6af27206.74dccc","name":"","url":"/mysite","method":"get","swaggerDoc":"","x":150,"y":240,"wires":[["4c783328.03dc2c"]]},{"id":"5de0bbd4.6c8574","type":"http in","z":"6af27206.74dccc","name":"","url":"/mysitepost","method":"post","swaggerDoc":"","x":170,"y":440,"wires":[["80321000.f2dc5","75913f37.78e6e"]]},{"id":"4c783328.03dc2c","type":"function","z":"6af27206.74dccc","name":"msg.url = \"mysitepost\";","func":"msg.url = \"mysitepost\";\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":240,"wires":[["b2f5bdf9.e09f1"]]},{"id":"80321000.f2dc5","type":"debug","z":"6af27206.74dccc","name":"mysitepost","active":true,"console":"false","complete":"payload","x":810,"y":440,"wires":[]},{"id":"8de9647.b8a9a98","type":"http response","z":"6af27206.74dccc","name":"","x":830,"y":400,"wires":[]},{"id":"b2972258.ecf54","type":"template","z":"6af27206.74dccc","name":"CSS","field":"payload.style","fieldType":"msg","format":"html","syntax":"mustache","template":"input[type=text], select {\n    width: 100%;\n    padding: 12px 20px;\n    margin: 8px 0;\n    display: inline-block;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    box-sizing: border-box;\n}\n\ninput[type=submit] {\n    width: 100%;\n    background-color: #4CAF50;\n    color: white;\n    padding: 14px 20px;\n    margin: 8px 0;\n    border: none;\n    border-radius: 4px;\n    cursor: pointer;\n}\n\ninput[type=submit]:hover {\n    background-color: #45a049;\n}\n\ndiv {\n    border-radius: 5px;\n    background-color: #f2f2f2;\n    padding: 20px;\n}","x":550,"y":340,"wires":[["f3b55ea2.f4d51"]]},{"id":"b2f5bdf9.e09f1","type":"template","z":"6af27206.74dccc","name":"JavaScript","field":"payload.script","fieldType":"msg","format":"javascript","syntax":"plain","template":"$(document).ready(function(e) {\n    \n    $(\"form[ajax=true]\").submit(function(e) {\n        \n        e.preventDefault();\n        \n        var form_data = $(this).serialize();\n        var form_url = $(this).attr(\"action\");\n        var form_method = $(this).attr(\"method\").toUpperCase();\n        \n        $(\"#loadingimg\").show();\n        \n        $.ajax({\n            url: form_url, \n            type: form_method,      \n            data: form_data,     \n            cache: false,\n            success: function(returnhtml){                          \n                $(\"#result\").html(returnhtml); \n                $(\"#loadingimg\").hide();                    \n            }           \n        });    \n        \n    });\n    \n});","x":390,"y":340,"wires":[["b2972258.ecf54"]]},{"id":"d2c0bc2a.05a02","type":"http response","z":"6af27206.74dccc","name":"","x":830,"y":340,"wires":[]},{"id":"f3b55ea2.f4d51","type":"template","z":"6af27206.74dccc","name":"HTML","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n  <head>\n    <title>My Site</title>\n    <meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\">\n    <meta charset=\"utf-8\">\n    <script src=\"http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js\"></script>\n    <style>{{{payload.style}}}</style>\n  </head>\n  \n\n    <h2>Using CSS to style an HTML form with AJAX POST and Node-RED</h2>\n    <h4><a href=\"http://www.internetoflego.com\">Internet of LEGO</a></h4>\n\n<div>\n  <form method=\"post\" action=\"/{{url}}\" ajax=\"true\">\n    <label for=\"fname\">First Name</label>\n    <input type=\"text\" id=\"fname\" name=\"firstname\">\n\n    <label for=\"lname\">Last Name</label>\n    <input type=\"text\" id=\"lname\" name=\"lastname\">\n\n    <label for=\"country\">Country</label>\n    <select id=\"country\" name=\"country\">\n      <option value=\"uk\">United Kingdom</option>\n      <option value=\"canada\">Canada</option>\n      <option value=\"usa\">USA</option>\n    </select>\n  \n    <input type=\"submit\" value=\"Submit\">\n  </form>\n</div>\n<div>\n    <span id=\"result\"></span>\n</div>\n\n</body>\n</html>\n<script>{{{payload.script}}}</script>","x":690,"y":340,"wires":[["d2c0bc2a.05a02"]]},{"id":"57316751.8bd948","type":"comment","z":"6af27206.74dccc","name":"Login Form","info":"","x":350,"y":300,"wires":[]},{"id":"ad88b28c.bc842","type":"function","z":"6af27206.74dccc","name":"return msg.payload to client","func":"msg.payload = 'The following data was submitted and available in the msg.payload: '+msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":400,"wires":[["8de9647.b8a9a98"]]},{"id":"42a9d329.9cdf6c","type":"comment","z":"6af27206.74dccc","name":"Inject msg object properties","info":"","x":360,"y":200,"wires":[]},{"id":"75913f37.78e6e","type":"json","z":"6af27206.74dccc","name":"","x":370,"y":400,"wires":[["ad88b28c.bc842"]]},{"id":"86c08a83.385758","type":"comment","z":"6af27206.74dccc","name":"Website","info":"","x":130,"y":160,"wires":[]},{"id":"111485fa.14c4aa","type":"comment","z":"6af27206.74dccc","name":"Form Submission","info":"","x":160,"y":380,"wires":[]},{"id":"3c029955.901626","type":"comment","z":"6af27206.74dccc","name":"Node-RED Public Site - README","info":"This Flow demonstrates how to create\na simple frontend webpage with Node-RED.\n\nThe public facing page consists of the \nclient side JavaScript, CSS and HTML. \n\nThe important technique is how the mustache \ntemplates are used. Each template will set the\n\"property\" relative to the content. \n\nThe CSS node sets the \"msg.payload.style\" property.\nThe JavaScript node sets the \"msg.payload.script\" property.\nThe HTML node then includes these properties \n<script>{{{payload.script}}}</script>\n<style>{{{payload.style}}}</style>\n\n\nThis example was created by http://www.InternetofLEGO.com\n\n","x":460,"y":60,"wires":[]}]

Flow Info

Created 7 years, 9 months ago
Updated 3 years, 4 months ago
Rating: 4.166666666666667 6

Owner

Actions

Rate:

Node Types

Core
  • comment (x5)
  • debug (x1)
  • function (x2)
  • http in (x2)
  • http response (x2)
  • json (x1)
  • template (x3)

Tags

  • html
  • javascript
  • css
  • ajax
  • node-red
  • form
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option