Text input into table ui

Dear all, I would like to add data into table from the text input. I would like to have all row fill then move next row. but the row cannot fill in. the previous value missing when I sent new value.
Please help me. Thank you

[{"id":"c4f39e9c.3642f8","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"59a0cfff.9bcb","type":"debug","z":"c4f39e9c.3642f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1270,"y":420,"wires":[]},{"id":"4c5c306f.e02298","type":"ui_table","z":"c4f39e9c.3642f8","group":"b070d416.db371","name":"Table","order":1,"width":16,"height":7,"columns":[],"outputs":1,"cts":true,"x":1110,"y":420,"wires":[["59a0cfff.9bcb"]]},{"id":"dd154dab.fcd418","type":"function","z":"c4f39e9c.3642f8","name":"","func":"msg.payload = [\n    {\"Date\":msg.payload.a,\"Seq\":msg.payload.b,\"Model\":msg.payload.c,\"Color\":msg.payload.d,\"Plan\":msg.payload.e},\n\n]\n\nmsg.ui_control =  {\n    \"tabulator\":{\n        \"columnResized\":\"function(column){var newColumn = {         field: column._column.field,         visible: column._column.visible,         width: column._column.width,         widthFixed: column._column.widthFixed,         widthStyled: column._column.widthStyled     }; this.send({topic:this.config.topic,ui_control:{callback:'columnResized',columnWidths:newColumn}}); }\",\n        \"columnMoved\":\"function(column, columns){     var newColumns=[];     columns.forEach(function (column) {         newColumns.push({'field': column._column.field});     });     this.send({topic:this.config.topic,ui_control:{callback:'columnMoved',columns:newColumns}}); }\",\n        \"groupHeader\":\"function (value, count, data, group) {return value + \\\"<span style='color:#d00; margin-left:10px;'>(\\\" + count + \\\" Termostat\\\"+((count>1) ? \\\"e\\\" : \\\"\\\") + \\\")</span>\\\";}\",\n        \"columns\":[\n            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Date\",\"field\":\"Date\",\"width\":100, \"editor\":\"input\"},\n            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Sequence\",\"field\":\"Seq\",\"width\":100,\"align\":\"center\"},\n            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Model\",\"field\":\"Model\",\"width\":100,\"align\":\"center\"},\n            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Color\",\"field\":\"Color\",\"width\":100,\"align\":\"center\"},\n            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Plan\",\"field\":\"Plan\",\"width\":100,\"align\":\"center\"},\n        ],\n        //\"cellEdited\":\"function(cell){this.send({ui_control:{callback:'cellEdited'},payload:cell.getValue(),oldValue:cell.getOldValue(),field:cell.getColumn().getField(),id:cell.getRow().getCell('id').getValue()}); }\",\n        \"cellEdited\":\"function(cell){var change = {newValue:cell.getValue()};this.send({topic:this.config.topic,ui_control:{callback:'cellEdited',changes:change}});}\",\n        \"layout\":\"fitColumns\",\n        \"movableColumns\":true,\n        \"groupBy\":\"\"\n    },\n    \"customHeight\":12\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":940,"y":420,"wires":[["4c5c306f.e02298","439fe655ba8afb1d"]]},{"id":"cf058e1a.c30368","type":"inject","z":"c4f39e9c.3642f8","name":"reset table","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[]","payloadType":"json","x":960,"y":380,"wires":[["4c5c306f.e02298"]]},{"id":"d981ae02a6277cee","type":"ui_template","z":"c4f39e9c.3642f8","group":"168649544304a700","name":"Virtual Keyboard","order":2,"width":0,"height":0,"format":"<script> \n    \n// the semi-colon before function invocation is a safety net against concatenated\n// scripts and/or other plugins which may not be closed properly.\n; (function ($, window, document, undefined) {\n\n    // undefined is used here as the undefined global variable in ECMAScript 3 is\n    // mutable (ie. it can be changed by someone else). undefined isn't really being\n    // passed in so we can ensure the value of it is truly undefined. In ES5, undefined\n    // can no longer be modified.\n\n    // window and document are passed through as local variable rather than global\n    // as this (slightly) quickens the resolution process and can be more efficiently\n    // minified (especially when both are regularly referenced in your plugin).\n\n    // Create the defaults once\n    var pluginName = \"jkeyboard\",\n        defaults = {\n            layout: \"english\",\n            input: $('#input'),\n            customLayouts: {\n                selectable: []\n            },\n        };\n\n\n    var function_keys = {\n        backspace: {\n            text: 'DEL',\n        },\n        return: {\n            text: 'Enter'\n        },\n        shift: {\n            text: 'Shift'\n        },\n        space: {\n            text: 'Space'\n        },\n        numeric_switch: {\n            text: '123',\n            command: function () {\n                this.createKeyboard('numeric');\n                this.events();\n            }\n        },\n        layout_switch: {\n            text: '<i class=\"fa fa-keyboard-o\" aria-hidden=\"true\"></i>',\n            command: function () {\n                var l = this.toggleLayout();\n                this.createKeyboard(l);\n                this.events();\n            }\n        },\n        character_switch: {\n            text: 'ABC',\n            command: function () {\n                this.createKeyboard(layout);\n                this.events();\n            }\n        },\n        symbol_switch: {\n            text: '#+=',\n            command: function () {\n                this.createKeyboard('symbolic');\n                this.events();\n            }\n        }\n    };\n\n\n    var layouts = {\n        selectable: ['azeri', 'english', 'russian','french', 'emoji'],\n        azeri: [\n            ['q', 'ü', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'ö', 'ğ'],\n            ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ı', 'ə'],\n            ['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'ç', 'ş', 'backspace'],\n            ['numeric_switch', 'layout_switch', 'space', 'return']\n        ],\n        english: [\n            ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',],\n            ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',],\n            ['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'backspace'],\n            ['numeric_switch', 'layout_switch', 'space', 'return']\n        ],\n        russian: [\n            ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х'],\n            ['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'],\n            ['shift', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', 'backspace'],\n            ['numeric_switch', 'layout_switch', 'space', 'return']\n        ],\n        french: [\n            ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',],\n            ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l','à','ç'],\n            ['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm','é','è', 'backspace'],\n            ['numeric_switch', 'layout_switch', 'space', 'return']\n        ],\n        emoji: [\n            ['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊',],\n            ['😋', '😎', '😍', '😘', 'g', 'h', 'j', 'k', 'l','à','ç'],\n            ['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm','é','è', 'backspace'],\n            ['numeric_switch', 'layout_switch', 'space', 'return']\n        ],            \n        numeric: [\n            ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\n            ['-', '/', ':', ';', '(', ')', '$', '&', '@', '\"'],\n            ['symbol_switch', '.', ',', '?', '!', \"'\", 'backspace'],\n            ['character_switch', 'layout_switch', 'space', 'return'],\n        ],\n        numbers_only: [\n            ['1', '2', '3',],\n            ['4', '5', '6',],\n            ['7', '8', '9',],\n            ['0', 'backspace', 'return'],\n        ],\n        symbolic: [\n            ['[', ']', '{', '}', '#', '%', '^', '*', '+', '='],\n            ['_', '\\\\', '|', '~', '<', '>'],\n            ['numeric_switch', '.', ',', '?', '!', \"'\", 'backspace'],\n            ['character_switch', 'layout_switch', 'space', 'return'],\n\n        ]\n    }\n\n    var shift = false, capslock = false, layout = 'english', layout_id = 0;\n\n    // The actual plugin constructor\n    function Plugin(element, options) {\n        this.element = element;\n        // jQuery has an extend method which merges the contents of two or\n        // more objects, storing the result in the first object. The first object\n        // is generally empty as we don't want to alter the default options for\n        // future instances of the plugin\n        this.settings = $.extend({}, defaults, options);\n        // Extend & Merge the cusom layouts\n        layouts = $.extend(true, {}, this.settings.customLayouts, layouts);\n        if (Array.isArray(this.settings.customLayouts.selectable)) {\n            $.merge(layouts.selectable, this.settings.customLayouts.selectable);\n        }\n        this._defaults = defaults;\n        this._name = pluginName;\n        this.init();\n    }\n\n    Plugin.prototype = {\n        init: function () {\n            layout = this.settings.layout;\n            this.createKeyboard(layout);\n            this.events();\n        },\n\n        setInput: function (newInputField) {\n            this.settings.input = newInputField;\n        },\n\n        createKeyboard: function (layout) {\n            shift = false;\n            capslock = false;\n\n            var keyboard_container = $('<ul/>').addClass('jkeyboard'),\n                me = this;\n\n            layouts[layout].forEach(function (line, index) {\n                var line_container = $('<li/>').addClass('jline');\n                line_container.append(me.createLine(line));\n                keyboard_container.append(line_container);\n            });\n\n            $(this.element).html('').append(keyboard_container);\n        },\n\n        createLine: function (line) {\n            var line_container = $('<ul/>');\n\n            line.forEach(function (key, index) {\n                var key_container = $('<li/>').addClass('jkey').data('command', key);\n\n                if (function_keys[key]) {\n                    key_container.addClass(key).html(function_keys[key].text);\n                }\n                else {\n                    key_container.addClass('letter').html(key);\n                }\n\n                line_container.append(key_container);\n            })\n\n            return line_container;\n        },\n\n        events: function () {\n            var letters = $(this.element).find('.letter'),\n                shift_key = $(this.element).find('.shift'),\n                space_key = $(this.element).find('.space'),\n                backspace_key = $(this.element).find('.backspace'),\n                return_key = $(this.element).find('.return'),\n\n                me = this,\n                fkeys = Object.keys(function_keys).map(function (k) {\n                    return '.' + k;\n                }).join(',');\n\n            letters.on('click', function () {\n                me.type((shift || capslock) ? $(this).text().toUpperCase() : $(this).text());\n            });\n\n            space_key.on('click', function () {\n                me.type(' ');\n            });\n\n            return_key.on('click', function () {\n                me.enter();\n            });\n\n            backspace_key.on('click', function () {\n                me.backspace();\n            });\n\n            shift_key.on('click', function () {\n                if (capslock) {\n                    me.toggleShiftOff();\n                    capslock = false;\n                } else {\n                    me.toggleShiftOn();\n                }\n            }).on('dblclick', function () {\n                capslock = true;\n            });\n\n\n            $(fkeys).on('click', function () {\n                var command = function_keys[$(this).data('command')].command;\n                if (!command) return;\n\n                command.call(me);\n            });\n        },\n\n        type: function (key) {\n            var input = this.settings.input,\n                val = input.val(),\n                input_node = input.get(0),\n                start = input_node.selectionStart,\n                end = input_node.selectionEnd;\n\n            var max_length = $(input).attr(\"maxlength\");\n            if (start == end && end == val.length) {\n                if (!max_length || val.length < max_length) {\n                    input.val(val + key);\n                    input.change()\n                    $('#vkeyname').text(val + key)\n                }\n            } else {\n                if (input_node.type == \"text\"){\n                    var new_string = this.insertToString(start, end, val, key);\n                    input.val(new_string);\n                    start++;\n                    end = start;\n                    input_node.setSelectionRange(start, end);\n                    input.change()\n                }else if (input_node.type == \"number\"){\n                    input.val(val + key);\n                }else{\n                    input.val(val + key);\n                    input.change()\n                }\n                $('#vkeyname').text(val + key)\n                \n            }\n            input.trigger('focus');\n\n            if (shift && !capslock) {\n                this.toggleShiftOff();\n            }\n        },\n        \n        enter: function () {\n            var input = this.settings.input,\n                val = input.val();\n                input_node = input.get(0),\n                start = input_node.selectionStart,\n                end = input_node.selectionEnd;\n            if (input.type == \"text\"){\n                val = val + \"\\n\";\n                $('#vkeyname').text(val)\n            }\n            input.change()\n            input.focus()\n        },\n\n        backspace: function () {\n            var input = this.settings.input,\n                val = input.val();\n                input_node = input.get(0),\n                start = input_node.selectionStart,\n                end = input_node.selectionEnd;\n            if (input.type == \"text\"){\n                input.val(val.slice(0, start-1) + val.slice(start))\n                input_node.setSelectionRange(start-1, start-1);\n                //console.log(val)\n                $('#vkeyname').text(val)\n            }else{\n                input.val(val.slice(0,-1))\n                $('#vkeyname').text(val.slice(0,-1))\n            }\n            input.change()\n            //input.focus()\n        },\n\n        toggleShiftOn: function () {\n            var letters = $(this.element).find('.letter'),\n                shift_key = $(this.element).find('.shift');\n\n            letters.addClass('uppercase');\n            shift_key.addClass('active')\n            shift = true;\n        },\n\n        toggleShiftOff: function () {\n            var letters = $(this.element).find('.letter'),\n                shift_key = $(this.element).find('.shift');\n\n            letters.removeClass('uppercase');\n            shift_key.removeClass('active');\n            shift = false;\n        },\n\n        toggleLayout: function () {\n            layout_id = layout_id || 0;\n            var plain_layouts = layouts.selectable;\n            layout_id++;\n\n            var current_id = layout_id % plain_layouts.length;\n            var SelectedLayoutName = plain_layouts[current_id];\n            $('#vkeyname').text('V-Keyboard ' + SelectedLayoutName )\n            return plain_layouts[current_id];\n        },\n\n        insertToString: function (start, end, string, insert_string) {\n            return string.substring(0, start) + insert_string + string.substring(end, string.length);\n        }\n    };\n\n        /*\n\t\t// A really lightweight plugin wrapper around the constructor,\n\t\t// preventing against multiple instantiations\n\t\t$.fn[ pluginName ] = function ( options ) {\n\t\t\t\treturn this.each(function() {\n\t\t\t\t\t\tif ( !$.data( this, \"plugin_\" + pluginName ) ) {\n\t\t\t\t\t\t\t\t$.data( this, \"plugin_\" + pluginName, new Plugin( this, options ) );\n\t\t\t\t\t\t}\n\t\t\t\t});\n\t\t};\n        */\n        var methods = {\n            init: function(options) {\n                if (!this.data(\"plugin_\" + pluginName)) {\n                    this.data(\"plugin_\" + pluginName, new Plugin(this, options));\n                }\n            },\n\t\t\tsetInput: function(content) {\n\t\t\t\tthis.data(\"plugin_\" + pluginName).setInput($(content));\n            },\n            setLayout: function(layoutname) {\n                // change layout if it is not match current\n                object = this.data(\"plugin_\" + pluginName);\n                if (typeof(layouts[layoutname]) !== 'undefined' && object.settings.layout != layoutname) {\n                    object.settings.layout = layoutname;\n                    object.createKeyboard(layoutname);\n                    object.events();\n                };\n            },\n        };\n\n\t\t$.fn[pluginName] = function (methodOrOptions) {\n            if (methods[methodOrOptions]) {\n                return methods[methodOrOptions].apply(this.first(), Array.prototype.slice.call( arguments, 1));\n            } else if (typeof methodOrOptions === 'object' || ! methodOrOptions) {\n                // Default to \"init\"\n                return methods.init.apply(this.first(), arguments);\n            } else {\n                $.error('Method ' +  methodOrOptions + ' does not exist on jQuery.tooltip');\n            }\n        };\n\n})(jQuery, window, document);\n</script>\n<style>\n    .jkeyboard {\n  display: inline-block;\n}\n.jkeyboard, .jkeyboard .jline, .jkeyboard .jline ul {\n  display: block;\n  margin: 0;\n  padding: 0;\n}\n.jkeyboard .jline {\n  text-align: center;\n  margin-left: -14px;\n}\n.jkeyboard .jline ul li {\n  font-family: arial, sans-serif;\n  font-size: 20px;\n  display: inline-block;\n  border: 1px solid #468db3;\n  -webkit-box-shadow: 0 0 3px #468db3;\n  -webkit-box-shadow: inset 0 0 3px #468db3;\n  margin: 5px 0 1px 6px;\n  color: #000000;\n  border-radius: 5px;\n  width: 52px;\n  height: 52px;\n  box-sizing: border-box;\n  text-align: center;\n  line-height: 52px;\n  overflow: hidden;\n  cursor: pointer;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: -moz-none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.jkeyboard .jline ul li.uppercase {\n  text-transform: uppercase;\n}\n.jkeyboard .jline ul li:hover, .jkeyboard .jline ul li:active {\n  background-color: #185a82;\n}\n.jkeyboard .jline .return {\n  width: 80px;\n}\n.jkeyboard .jline .space {\n  width: 366px;\n}\n.jkeyboard .jline .numeric_switch {\n  width: 65px;\n}\n.jkeyboard .jline .layout_switch {\n}\n.jkeyboard .jline .shift {\n  width: 60px;\n}\n.jkeyboard .jline .backspace {\n  width: 69px;\n}\n</style>\n\n\n\n\n<style>\nbody {font-family: Arial, Helvetica, sans-serif;}\n\n.nr-dashboard-theme .nr-dashboard-template .md-button:not(:first-of-type) {\n    margin-top: 0px;\n}\n\n/* The Modal (background) */\n.modal {\n    display: none; /* Hidden by default */\n    position: fixed; /* Stay in place */\n    opacity:0.99;\n    z-index: 100; /* Sit on top */\n    left: 0;\n    top: 0;\n    width: 100%; /* Full width */\n    height: 100%; /* Full height */\n    overflow: auto; /* Enable scroll if needed */\n    background-color: rgb(0,0,0); /* Fallback color */\n    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n}\n\n/* Modal Content */\n.modal-content {\n    position: fixed;\n    background-color: #fefefe;\n    margin: auto;\n    padding: 0;\n    bottom: 0%;\n    left: 50%;\n    transform: translate(-50%, 0%);\n    border: 1px solid #888;\n    width: fit-content;\n    max-width: 100%;\n    max-height: 100%;\n    box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);\n    -webkit-animation-name: animate;\n    -webkit-animation-duration: 0.4s;\n    animation-name: animate;\n    animation-duration: 0.4s\n}\n\n/* Add Animation */\n@-webkit-keyframes animate {\n    from {bottom:100%; opacity:0} \n    to {bottom:0%; opacity:1}\n}\n\n@keyframes animate {\n    from {bottom:100%; opacity:0}\n    to {bottom:0%; opacity:1}\n}\n\n/* The Close Button */\n.close {\n    color: black;\n    float: right;\n    font-size: 28px;\n    font-weight: bold;\n}\n\n.close:hover,\n.close:focus {\n    color: #000;\n    text-decoration: none;\n    cursor: pointer;\n}\n\n.modal-header {\n    padding: 2px 16px;\n    background-color: aliceblue;\n    color: white;\n}\n\n.modal-body {padding: 2px 16px;}\n\n.modal-footer {\n    padding: 2px 16px;\n    background-color: #5cb85c;\n    color: white;\n}\n</style>\n\n<!-- The Modal -->\n<div id=\"myModal\" class=\"modal\">\n\n  <!-- Modal content -->\n  <div class=\"modal-content\">\n      <div class=\"modal-header\">\n      <span class=\"close\" onclick=\"closeModal()\">&times;</span>\n      <h2 id=\"vkeyname\" style=\"background-color: aliceblue !important; color: black !important; text-align: center; min-height: 30px;\">V-Keyboard</h2>\n    </div>\n    <div class=\"modal-body\">\n        <div id=\"keyboard\"></div>\n        <div>\n        </div>\n    </div>\n  </div>\n</div>\n\n\n<script>\n    // Get the modal\nvar modal = document.getElementById('myModal');\n\n/*\n$('input[type=text]').click(function () {\n    $('#keyboard').unbind().removeData();\n        $('#keyboard').jkeyboard({\n            layout: \"english\",\n            input: $('#'+$(this).attr('id'))\n    });\n});\n\n$('input[type=number]').click(function () {\n    $('#keyboard').unbind().removeData();\n        $('#keyboard').jkeyboard({\n            layout: \"numbers_only\",\n            input: $('#'+$(this).attr('id'))\n    });\n});\n*/\n\nvar inputTags;\nvar inputType;\n\nvar getinputs = function() {\n    inputTags = document.getElementsByTagName(\"input\");\n    console.log(inputTags)\n    for (var i = 0; i < inputTags.length; i++) {\n        inputTags[i].addEventListener('click', openModal, false)\n    }\n}\n\nsetTimeout(function(){ getinputs(); }, 1000);\n\nvar inputTarget;\n\nvar openModal = function() {\n    inputType = event.target.type\n    inputTarget = event.target\n    var layoutName;\n    if (inputType == \"number\"){\n        //inputTarget.type = \"number\" //hack because chrome doesn't allow setselection in number inputs\n        //inputTarget.value = \"\"\n        layoutName = \"numbers_only\"\n    }else{\n        layoutName = \"english\"\n    }\n    $('#vkeyname').text(event.target.value)\n    $('#keyboard').unbind().removeData();\n    modal.style.display = \"block\";\n    $('#keyboard').jkeyboard({\n        layout: layoutName,\n        input: $('#'+$(this).attr('id'))\n    });\n}\n\n\n// Get the <span> element that closes the modal\nvar span = document.getElementsByClassName(\"close\")[0];\n\n// When the user clicks on <span> (x), close the modal\n//span.onclick = function(event) {\n  //closeModal()\n//}\n\n// When the user clicks anywhere outside of the modal, close it\nwindow.onclick = function(event) {\n    var source = event.target;\n    if (source == modal || source == span) {\n        closeModal(source)\n    }\n};\n\nvar closeModal = function(source){\n    //console.log(\"closing\")\n    modal.style.display = \"none\";\n   \n    if (inputType == \"number\"){\n        inputTarget.type = \"number\" //hack because chrome doesn't allow selectionstart on number inputs\n    }\n}\n\n</script>\n<script>\n\nvar clickState = 1;\nvar btn = document.querySelector('.VK');\n\nbtn.addEventListener('click', function(){\n\n  if (clickState == 0) {\n    this.textContent = 'V-KeyBoard On';\n    modal = document.getElementById('myModal');\n    clickState = 1;\n  } else {\n    this.textContent = 'V-KeyBoard Off';\n    modal = document.getElementById('empty');\n    clickState = 0;\n  }\n\n});\n</script>\n\n<style>\n.VK{\n    position: fixed;\n    top: 60px;\n    right: 20px;\n    height: 30px;\n}\n</style>\n\n<div id=\"empty\"></div>\n<button class=\"VK\">V-KeyBoard On</button>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","className":"","x":240,"y":620,"wires":[[]]},{"id":"439fe655ba8afb1d","type":"debug","z":"c4f39e9c.3642f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1130,"y":480,"wires":[]},{"id":"04f534123010bab7","type":"ui_text_input","z":"c4f39e9c.3642f8","name":"","label":"Plan ","tooltip":"","group":"b070d416.db371","order":8,"width":4,"height":1,"passthru":false,"mode":"number","delay":"0","topic":"","sendOnBlur":true,"className":"","topicType":"str","x":210,"y":580,"wires":[["c95036f32fcd9ec9"]]},{"id":"850351a8558f1493","type":"ui_text_input","z":"c4f39e9c.3642f8","name":"","label":"Color","tooltip":"","group":"b070d416.db371","order":6,"width":4,"height":1,"passthru":false,"mode":"text","delay":"0","topic":"","sendOnBlur":true,"className":"","topicType":"str","x":210,"y":540,"wires":[["11ce553c6e299187"]]},{"id":"fd0a1188bb3a1af7","type":"ui_text_input","z":"c4f39e9c.3642f8","name":"","label":"Model","tooltip":"","group":"b070d416.db371","order":4,"width":4,"height":1,"passthru":false,"mode":"text","delay":"0","topic":"","sendOnBlur":true,"className":"","topicType":"str","x":210,"y":500,"wires":[["3814a63817616153"]]},{"id":"3814a63817616153","type":"change","z":"c4f39e9c.3642f8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.c","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":500,"wires":[["dd154dab.fcd418"]]},{"id":"11ce553c6e299187","type":"change","z":"c4f39e9c.3642f8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.d","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":540,"wires":[["dd154dab.fcd418"]]},{"id":"c95036f32fcd9ec9","type":"change","z":"c4f39e9c.3642f8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.e","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":580,"wires":[["dd154dab.fcd418"]]},{"id":"c255623bcd0380fc","type":"ui_text_input","z":"c4f39e9c.3642f8","name":"","label":"Sequence","tooltip":"","group":"b070d416.db371","order":2,"width":4,"height":1,"passthru":false,"mode":"text","delay":"0","topic":"","sendOnBlur":true,"className":"","topicType":"str","x":220,"y":460,"wires":[["2dc63a11acea42b2"]]},{"id":"2dc63a11acea42b2","type":"change","z":"c4f39e9c.3642f8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"payload.b","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":460,"wires":[["dd154dab.fcd418"]]},{"id":"8575b1bcf325d18e","type":"inject","z":"c4f39e9c.3642f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":230,"y":340,"wires":[["3814a63817616153"]]},{"id":"e9c18d82046c5948","type":"inject","z":"c4f39e9c.3642f8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2","payloadType":"num","x":230,"y":380,"wires":[["2dc63a11acea42b2"]]},{"id":"34792c435a88bfd7","type":"ui_spacer","z":"c4f39e9c.3642f8","name":"spacer","group":"74d3bc6d.dd56e4","order":3,"width":12,"height":1},{"id":"c9f0643f1be9b03d","type":"ui_spacer","z":"c4f39e9c.3642f8","name":"spacer","group":"74d3bc6d.dd56e4","order":5,"width":12,"height":1},{"id":"c37d1efb94450c48","type":"ui_spacer","z":"c4f39e9c.3642f8","name":"spacer","group":"74d3bc6d.dd56e4","order":7,"width":12,"height":1},{"id":"622579641140dd36","type":"ui_spacer","z":"c4f39e9c.3642f8","name":"spacer","group":"74d3bc6d.dd56e4","order":9,"width":12,"height":1},{"id":"b070d416.db371","type":"ui_group","name":"Table","tab":"dc73b853795f31e8","order":1,"disp":true,"width":"16","collapse":false,"className":""},{"id":"168649544304a700","type":"ui_group","name":"table-handler-demo #1","tab":"aad45b21eda0ccc1","order":2,"disp":true,"width":"9","collapse":true},{"id":"74d3bc6d.dd56e4","type":"ui_group","name":"Table","tab":"6fc9e7af.0b5ce8","order":1,"disp":true,"width":16,"collapse":false},{"id":"dc73b853795f31e8","type":"ui_tab","name":"HLYM","icon":"link","order":1,"disabled":false,"hidden":false},{"id":"aad45b21eda0ccc1","type":"ui_tab","name":"ui-table","icon":"dashboard","order":9,"disabled":false,"hidden":false},{"id":"6fc9e7af.0b5ce8","type":"ui_tab","name":"Tabletest","icon":"dashboard","order":16,"disabled":false,"hidden":false}]

You could use the ui-form and enter all the data at the same time

If you haven't yet, 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.

1 Like

As zenofmud mentioned I would use ui-form, too.
I took your example and turned it to my way of using ui-table:

[
    {
        "id": "fd3a93decc2a1270",
        "type": "tab",
        "label": "e.g. ui-table",
        "disabled": false,
        "info": ""
    },
    {
        "id": "ec34c6ada52855bd",
        "type": "change",
        "z": "fd3a93decc2a1270",
        "name": "Table Configuration",
        "rules": [
            {
                "t": "set",
                "p": "ui_control",
                "pt": "msg",
                "to": "$format := {\t   \"tabulator\": {\t        \"tableBuilt\":\"function(){this.tablebuilt = true;}\",\t        \"dataLoaded\":\"function(data){if(this.tablebuilt){this.tablebuilt=false; this.send({topic:'build table', ui_control:{callback:'tableBuilt'}})}else{this.send({topic:'success', ui_control:{callback:'setData'}, return:{command:'setData', arguments:[data]}})}}\",\t        \"columnResized\":\"function(column){var newColumn = {         field: column._column.field,         visible: column._column.visible,         width: column._column.width,         widthFixed: column._column.widthFixed,         widthStyled: column._column.widthStyled     }; this.send({topic:this.config.topic,ui_control:{callback:'columnResized',columnWidths:newColumn}}); }\",\t        \"columnMoved\":\"function(column, columns){     var newColumns=[];     columns.forEach(function (column) {         newColumns.push({'field': column._column.field});     });     this.send({topic:this.config.topic,ui_control:{callback:'columnMoved',columns:newColumns}}); }\",\t        \"groupHeader\":\"function (value, count, data, group) {return value + \\\"<span style='color:#d00; margin-left:10px;'>(\\\" + count + \\\" Termostat\\\"+((count>1) ? \\\"e\\\" : \\\"\\\") + \\\")</span>\\\";}\",\t        \"columns\":[\t            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Date\",\"field\":\"Date\",\"width\":100, \"editor\":\"input\"},\t            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Sequence\",\"field\":\"Seq\",\"width\":100,\"align\":\"center\"},\t            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Model\",\"field\":\"Model\",\"width\":100,\"align\":\"center\"},\t            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Color\",\"field\":\"Color\",\"width\":100,\"align\":\"center\"},\t            {\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Plan\",\"field\":\"Plan\",\"width\":100,\"align\":\"center\"}\t        ],\t        \"cellEdited\":\"function(cell){var change = {newValue:cell.getValue()};this.send({topic:this.config.topic,ui_control:{callback:'cellEdited',changes:change}});}\",\t        \"layout\":\"fitColumns\",\t        \"movableColumns\":true,\t        \"groupBy\":\"\"\t    },\t    \"customHeight\":12\t}",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "{}",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 630,
        "y": 220,
        "wires": [
            [
                "31731e53875dacf5"
            ]
        ],
        "icon": "node-red/cog.svg"
    },
    {
        "id": "863b8f9b8d52963d",
        "type": "inject",
        "z": "fd3a93decc2a1270",
        "name": "",
        "props": [
            {
                "p": "payload",
                "v": "-1",
                "vt": "num"
            },
            {
                "p": "topic",
                "v": "",
                "vt": "string"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "-1",
        "payloadType": "num",
        "x": 230,
        "y": 220,
        "wires": [
            [
                "ec34c6ada52855bd"
            ]
        ]
    },
    {
        "id": "29ee456cbd10be91",
        "type": "debug",
        "z": "fd3a93decc2a1270",
        "name": "TABLE",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1370,
        "y": 100,
        "wires": []
    },
    {
        "id": "31731e53875dacf5",
        "type": "ui_table",
        "z": "fd3a93decc2a1270",
        "group": "d04cb83acc2064af",
        "name": "Content",
        "order": 1,
        "width": "20",
        "height": "12",
        "columns": [],
        "outputs": 1,
        "cts": true,
        "x": 1140,
        "y": 220,
        "wires": [
            [
                "f18a891c4099b790",
                "29ee456cbd10be91"
            ]
        ]
    },
    {
        "id": "a2696265f95db3aa",
        "type": "ui_button",
        "z": "fd3a93decc2a1270",
        "name": "",
        "group": "21028a285361e1fc",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Clear Table",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "clear all",
        "topicType": "str",
        "x": 210,
        "y": 500,
        "wires": [
            [
                "821293d40021dc19"
            ]
        ]
    },
    {
        "id": "0f7aca16675ee795",
        "type": "ui_form",
        "z": "fd3a93decc2a1270",
        "name": "",
        "label": "New Item",
        "group": "21028a285361e1fc",
        "order": 1,
        "width": 0,
        "height": 0,
        "options": [
            {
                "label": "Sequence",
                "value": "Seq",
                "type": "text",
                "required": true,
                "rows": null
            },
            {
                "label": "Model",
                "value": "Model",
                "type": "text",
                "required": true,
                "rows": null
            },
            {
                "label": "Color",
                "value": "Color",
                "type": "text",
                "required": true,
                "rows": null
            },
            {
                "label": "Plan",
                "value": "Plan",
                "type": "number",
                "required": true,
                "rows": null
            }
        ],
        "formValue": {
            "Seq": "",
            "Model": "",
            "Color": "",
            "Plan": ""
        },
        "payload": "",
        "submit": "submit",
        "cancel": "cancel",
        "topic": "add item",
        "topicType": "str",
        "splitLayout": "",
        "className": "",
        "x": 220,
        "y": 660,
        "wires": [
            [
                "18dcb329f842183f"
            ]
        ]
    },
    {
        "id": "18dcb329f842183f",
        "type": "function",
        "z": "fd3a93decc2a1270",
        "name": "ID Generator",
        "func": "msg.payload.id = RED.util.generateId();\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 390,
        "y": 660,
        "wires": [
            [
                "821293d40021dc19"
            ]
        ]
    },
    {
        "id": "821293d40021dc19",
        "type": "change",
        "z": "fd3a93decc2a1270",
        "name": "delete socketid",
        "rules": [
            {
                "t": "delete",
                "p": "socketid",
                "pt": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 640,
        "y": 500,
        "wires": [
            [
                "fbe860b501639c1a"
            ]
        ]
    },
    {
        "id": "fbe860b501639c1a",
        "type": "function",
        "z": "fd3a93decc2a1270",
        "name": "Database",
        "func": "//db holds tabledata on server side\nlet db = context.get('db');\nif(db === undefined){\n    db = [];\n}\nswitch(msg.topic){\n    case 'add item':\n        msg.payload.Date = new Date().toLocaleDateString();\n        db.push(msg.payload);\n        context.set('db', db);\n        msg.payload={\n            command:\"addRow\",\n            arguments: [\n                [\n                    msg.payload\n                ],\n                false //false = add on end of list\n            ],\n            returnPromise: true\n        }\n        break;\n    case 'build table':\n        msg.payload={\n            command:\"setData\",\n            arguments: [\n                db\n            ],\n            returnPromise: false\n        }\n        break;\n    case 'clear all':\n        db = [];\n        context.set('db', db);\n        msg.payload={\n            command:\"setData\",\n            arguments: [\n                db\n            ],\n            returnPromise: false\n        }\n        break;\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 900,
        "y": 500,
        "wires": [
            [
                "35571d7bd35ac114",
                "31731e53875dacf5"
            ]
        ]
    },
    {
        "id": "35571d7bd35ac114",
        "type": "debug",
        "z": "fd3a93decc2a1270",
        "name": "DATABASE",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1130,
        "y": 500,
        "wires": []
    },
    {
        "id": "f18a891c4099b790",
        "type": "switch",
        "z": "fd3a93decc2a1270",
        "name": "",
        "property": "topic",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "build table",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 1370,
        "y": 220,
        "wires": [
            [
                "4d8aebc1b773d32e"
            ]
        ]
    },
    {
        "id": "4d8aebc1b773d32e",
        "type": "change",
        "z": "fd3a93decc2a1270",
        "name": "",
        "rules": [
            {
                "t": "delete",
                "p": "ui_control",
                "pt": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1420,
        "y": 300,
        "wires": [
            [
                "fbe860b501639c1a"
            ]
        ]
    },
    {
        "id": "d04cb83acc2064af",
        "type": "ui_group",
        "name": "Table",
        "tab": "635ba43dc8d01298",
        "order": 2,
        "disp": true,
        "width": "20",
        "collapse": false,
        "className": ""
    },
    {
        "id": "21028a285361e1fc",
        "type": "ui_group",
        "name": "Input",
        "tab": "635ba43dc8d01298",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "635ba43dc8d01298",
        "type": "ui_tab",
        "name": "example ui-table",
        "icon": "track_changes",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

In this code I try to hold the table on server side, also. You may skip this part.

2 Likes

I just spent the past month working with a problem similar to this. It doesn't seem easy at first, but that's because there are so many options to work with. You have two points of entry for getting data into your tables:

  1. From some kind of node outside the table (i.e. a function node or inject node)
  2. From inside your table node

If you're doing SIMPLE stuff and ONLY want the table and NO EXTRA FEATURES, you can easily do everything you want with a function node. Simply keep track of all the table rows as a persistent array in your function node by using context.set() and context.get() (look them up if you've never used them). That will keep your "table" in working memory. You can change values and assign new things to the array inside a function. Yes, there are other nodes that can do this for you, but you can do the same thing in a function with a single line of code in most cases, and customize how things are handled. Whenever you do something with the function, you just have your output be the array you're working with. Something like this:

//Function on start tab holds this:
var arrayStore = [];
context.set('arrayStore', arrayStore);

//Function on message tab holds something like this:
var arrTemp = context.get('arrayStore');
do.some.stuff.with.arrTemp();
context.set('arrayStore', arrTemp);
msg.payload = arrTemp;
return msg;

As long as you have your function output going into the input of your table node, it will display everything in your array, provided all your rows have the same columns. If you need persistence, simply attach file read and write nodes to your function to store and read the data.

The alternative is to work within your node directly. You can use something like Tabulator, which is what nodes like ui-table and ui-etable are built off of, or some other similar program. The advantage of this is you can simply copy/paste a lot of power from the examples listed on Tabulator's page and not worry about the nodes that would need to be attached, since everything is handled in the ui-template node. Disadvantage is it requires a little more to get data into and out of the ui-template node you would need to use to integrate it into your flows, at least in terms of knowledge. It's very simple to do with HTTP links. But the table can hold and manipulate all your data, then you can just export it if you need to interact with Node-Red at all. Adding a row is simply putting up a button to add a row and then entering everything you want to enter. When the row is full, click the button and go on. Or have it setup to automatically add a row if everything is populated in the last row of the table. The possibilities are endless.

1 Like

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