@Christian-Me wrote:
Version with ui_list. The only difference is the ui_List node and the save list function node.
So for every new property in best case you only need to wire in ui_Node and configure the switch and add new node, worst case add a special node to handle the output.
The feednack ist only needed for the name value to update the dropdoen list. all others will be ignored.[{"id":"5e92c20f.ec0a6c","type":"ui_text_input","z":"afaa0885.ad2718","name":"name","label":"","tooltip":"","group":"1727a207.b3522e","order":5,"width":6,"height":1,"passthru":false,"mode":"text","delay":"0","topic":"mySettings.heating.periods.name","x":610,"y":1280,"wires":[["40302cf4.7e27e4"]]},{"id":"4f49163c.5cf618","type":"ui_button","z":"afaa0885.ad2718","name":"uiDelete","group":"1727a207.b3522e","order":3,"width":1,"height":1,"passthru":false,"label":"","tooltip":"","color":"","bgcolor":"","icon":"delete","payload":"Wirklich löschen?","payloadType":"str","topic":"mySettings.heating.periods.uiDelete","x":620,"y":1220,"wires":[["d6348ffa.c8c09"]]},{"id":"64fa2ace.070df4","type":"function","z":"afaa0885.ad2718","name":"delete period","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getEntry(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not found\"});\n return;\n}\nvar name=currentProperty.name;\n\ntry {\n if (currentObject.deleteEntry(msg.topic)) {\n node.status({fill:\"green\",shape:\"dot\",text:name+\" deleted\"});\n } else {\n node.status({fill:\"green\",shape:\"dot\",text:name+\" NOT deleted\"});\n }\n return msg;\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"ups, something gone wrong.\"});\n console.log(err);\n} ","outputs":1,"noerr":0,"x":910,"y":1220,"wires":[["8e2785df.4b1f38"]]},{"id":"6940f151.ee7af","type":"ui_date_picker","z":"afaa0885.ad2718","name":"start","label":"","group":"1727a207.b3522e","order":7,"width":6,"height":1,"passthru":false,"topic":"mySettings.heating.periods.start","x":610,"y":1340,"wires":[["40302cf4.7e27e4"]]},{"id":"fa154658.7c86d8","type":"ui_date_picker","z":"afaa0885.ad2718","name":"end","label":"","group":"1727a207.b3522e","order":9,"width":6,"height":1,"passthru":false,"topic":"mySettings.heating.periods.end","x":610,"y":1400,"wires":[["40302cf4.7e27e4"]]},{"id":"74aa6cbd.107304","type":"ui_text","z":"afaa0885.ad2718","group":"1727a207.b3522e","order":4,"width":2,"height":1,"name":"Name:","label":"Name:","format":"{{msg.payload}}","layout":"row-spread","x":130,"y":1280,"wires":[]},{"id":"d21d39f.cf447c8","type":"ui_text","z":"afaa0885.ad2718","group":"1727a207.b3522e","order":6,"width":2,"height":1,"name":"Start:","label":"Anfang:","format":"{{msg.payload}}","layout":"row-spread","x":130,"y":1340,"wires":[]},{"id":"bf3c7ebf.f89d4","type":"ui_text","z":"afaa0885.ad2718","group":"1727a207.b3522e","order":8,"width":2,"height":1,"name":"End:","label":"Ende:","format":"{{msg.payload}}","layout":"row-spread","x":130,"y":1400,"wires":[]},{"id":"4e308951.08be78","type":"ui_dropdown","z":"afaa0885.ad2718","name":"uiDropdown","label":"","tooltip":"","place":"Tage auswählen","group":"1727a207.b3522e","order":1,"width":6,"height":1,"passthru":true,"options":[],"payload":"","topic":"mySettings.heating.periods.uiDropdown","x":630,"y":1100,"wires":[["3404a4d4.23919c"]]},{"id":"4bc14249.f80a5c","type":"function","z":"afaa0885.ad2718","name":"update","func":"var msgDropdown={};\nvar msgName={};\nvar msgList={};\nvar msgParameter=[];\n\nvar topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar keyword = topicParts.pop();\nvar propertyTopic = msg.topic.slice(0,msg.topic.lastIndexOf('.'));\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n return;\n}\n\nmsgDropdown.topic=msg.topic;\n\ntry {\n // fill an array for all parameters in list if exiting\n if (currentProperty.list) { \n for (var item in currentProperty.list[currentProperty.uiPointer]) {\n if (!item.startsWith('ui')) \n msgParameter.push({\"payload\":currentProperty.list[currentProperty.uiPointer][item], \"topic\": propertyTopic+'.'+item});\n }\n } \n switch (keyword) {\n case \"uiDropdown\":\n node.status({fill:\"green\",shape:\"dot\",text:\"Dropdown updated!\"});\n return [null,msgParameter]; // update all parameters\n case \"uiAdd\":\n msgDropdown.payload=currentProperty.uiPointer;\n node.status({fill:\"green\",shape:\"dot\",text:\"new entry nr=\"+currentProperty.uiPointer});\n return [msgDropdown,null]; // update only dropdown, parametes will follw next call\n case \"uiDelete\":\n msgDropdown.payload=\"init\";\n node.status({fill:\"green\",shape:\"dot\",text:\"entry deleted\"});\n return [msgDropdown,null]; // update only dropdown, parametes will follw next call\n case \"name\":\n msgDropdown.payload=currentProperty.uiPointer;\n node.status({fill:\"green\",shape:\"dot\",text:\"entry renamed!\"});\n return [msgDropdown,null]; // update only dropdown\n }\n \n node.status({fill:\"gray\",shape:\"dot\",text:msg.topic+\"=\"+msg.payload});\n return null;\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong. (\"+keyword+\")\"});\n console.log(err);\n} ","outputs":2,"noerr":0,"x":210,"y":1200,"wires":[["1273f17e.cacfff"],["126c086f.d5ee48"]]},{"id":"8708046a.a91488","type":"link out","z":"afaa0885.ad2718","name":"updatePeriod","links":["d3e12acd.ca7e78"],"x":1035,"y":1340,"wires":[]},{"id":"d3e12acd.ca7e78","type":"link in","z":"afaa0885.ad2718","name":"updatePeriod","links":["8708046a.a91488","8ff23ed0.e7991","480be8a7.ca3858","8e2785df.4b1f38","facf168d.a84228"],"x":115,"y":1200,"wires":[["4bc14249.f80a5c"]]},{"id":"8ff23ed0.e7991","type":"link out","z":"afaa0885.ad2718","name":"updatePeriod","links":["d3e12acd.ca7e78"],"x":1035,"y":1100,"wires":[]},{"id":"40302cf4.7e27e4","type":"function","z":"afaa0885.ad2718","name":"save Data","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getEntry(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not found\"});\n return;\n}\nvar propertyName=msg.topic.slice(msg.topic.lastIndexOf('.')+1);\n\ntry {\n // make shure your topic is set correctly in your ui nodes(s): objectName.propertyName\n currentProperty[propertyName]=msg.payload;\n\n node.status({fill:\"green\",shape:\"dot\",text:propertyName+\"=\"+msg.payload+\"!\"});\n return msg;\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong.\"});\n console.log(err);\n} ","outputs":1,"noerr":0,"x":900,"y":1340,"wires":[["8708046a.a91488"]]},{"id":"1273f17e.cacfff","type":"function","z":"afaa0885.ad2718","name":"fill dropdown","func":"var topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar keyword = topicParts.pop();\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n return;\n}\n\n//try {\n console.log(currentProperty.list!==undefined)\n if (currentProperty.list!==undefined) {\n msg.options=[];\n var listEntry={};\n currentProperty.list.forEach(function(item,index){\n listEntry={};\n listEntry[item.name]=String(index);\n msg.options.push(listEntry);\n })\n msg.options.sort();\n \n if (!currentProperty.list[currentProperty.uiPointer]) {\n if (currentProperty.list.length>0){\n currentProperty.uiPointer=0; // reset to first\n msg.payload=currentProperty.uiPointer;\n } else { // no period existing\n delete msg.payload;\n }\n } else msg.payload=currentProperty.uiPointer;\n \n node.status({fill:\"green\",shape:\"dot\",text:\"done!\"});\n } else {\n node.status({fill:\"yellow\",shape:\"dot\",text:\"object.list empty\"});\n }\n return msg;\n\n/*} catch (err) {\n node.status({fill:\"yellow\",shape:\"dot\",text:\"No list entry\"});\n return msg;\n} */","outputs":1,"noerr":0,"x":430,"y":1100,"wires":[["4e308951.08be78"]]},{"id":"9b8345ab.734018","type":"inject","z":"afaa0885.ad2718","name":"initalize","topic":"mySettings.heating.periods.null","payload":"uiInit","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":120,"y":1100,"wires":[["cc912830.ac5188"]]},{"id":"20d22b21.441424","type":"function","z":"afaa0885.ad2718","name":"save List","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getEntry(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not found\"});\n return;\n}\nvar propertyName=msg.topic.slice(msg.topic.lastIndexOf('.')+1);\n\ntry {\n currentProperty.days.forEach(function (item,index) {\n if (item.title.includes(msg.payload.title)) {\n item.isChecked=msg.payload.isChecked;\n node.status({fill:\"green\",shape:\"dot\",text:msg.payload.title+\"=\"+msg.payload.isChecked});\n return msg;\n }\n });\n // node.status({fill:\"yellow\",shape:\"dot\",text:msg.payload.title+\" not found\"});\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong.\"});\n console.log(err);\n} ","outputs":1,"noerr":0,"x":900,"y":1460,"wires":[[]]},{"id":"3404a4d4.23919c","type":"function","z":"afaa0885.ad2718","name":"set editPeriod","func":"var topicParts=msg.topic.split('.');\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.getObject(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n return;\n}\n\ntry {\n currentProperty.uiPointer=Number(msg.payload);\n node.status({fill:\"green\",shape:\"dot\",text:msg.payload+\"!\"});\n return msg;\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"ups, somthing gone wrong.\"});\n console.log(err);\n} ","outputs":1,"noerr":0,"x":920,"y":1100,"wires":[["8ff23ed0.e7991"]]},{"id":"8e2785df.4b1f38","type":"link out","z":"afaa0885.ad2718","name":"updatePeriod","links":["d3e12acd.ca7e78"],"x":1035,"y":1220,"wires":[]},{"id":"8cd0c53e.487bf8","type":"ui_button","z":"afaa0885.ad2718","name":"uiAdd","group":"1727a207.b3522e","order":2,"width":1,"height":1,"passthru":false,"label":"","tooltip":"","color":"","bgcolor":"","icon":"playlist_add","payload":"unbenannt","payloadType":"str","topic":"mySettings.heating.periods.uiAdd","x":610,"y":1160,"wires":[["e1f0305c.a78a"]]},{"id":"e1f0305c.a78a","type":"function","z":"afaa0885.ad2718","name":"add new","func":"node.status({});\nvar currentObject= global.get(msg.topic.slice(0,msg.topic.indexOf('.')),\"file\");\nif (!currentObject) return;\nvar currentProperty=currentObject.newObject(msg.topic);\nif (!currentProperty) {\n node.status({fill:\"red\",shape:\"dot\",text: msg.topic+\" not created\"});\n return;\n}\n\n// move Pointer to new entry\ncurrentProperty.uiPointer=currentProperty.list.length-1\nvar newItem = currentProperty.list[currentProperty.uiPointer];\n\n// initialize property object\nnewItem.name=msg.payload;\n\n// fill defaults \nnewItem.start=new Date();\nnewItem.end=new Date();\nnewItem.days=[]\nnewItem.days.push({title:\"Montag\", isChecked: false});\nnewItem.days.push({title:\"Dienstag\", isChecked: false});\nnewItem.days.push({title:\"Mittwoch\", isChecked: false});\nnewItem.days.push({title:\"Donnerstag\", isChecked: false});\nnewItem.days.push({title:\"Freitag\", isChecked: false});\nnewItem.days.push({title:\"Samstag\", isChecked: false});\nnewItem.days.push({title:\"Sonntag\", isChecked: false});\n\n// send output\nnode.status({fill:\"green\",shape:\"dot\",text:msg.payload+\" saved\"});\nreturn msg;","outputs":1,"noerr":0,"x":900,"y":1160,"wires":[["facf168d.a84228"]]},{"id":"facf168d.a84228","type":"link out","z":"afaa0885.ad2718","name":"updatePeriod","links":["d3e12acd.ca7e78"],"x":1035,"y":1160,"wires":[]},{"id":"126c086f.d5ee48","type":"switch","z":"afaa0885.ad2718","name":"topic","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"mySettings.heating.periods.name","vt":"str"},{"t":"eq","v":"mySettings.heating.periods.start","vt":"str"},{"t":"eq","v":"mySettings.heating.periods.end","vt":"str"},{"t":"eq","v":"mySettings.heating.periods.days","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":410,"y":1380,"wires":[["5e92c20f.ec0a6c"],["6940f151.ee7af"],["fa154658.7c86d8"],["ea72c8b7.6b8be8"]]},{"id":"d6348ffa.c8c09","type":"ui_toast","z":"afaa0885.ad2718","position":"dialog","displayTime":"3","highlight":"","sendall":false,"outputs":1,"ok":"OK","cancel":"","topic":"","name":"Delete?","x":760,"y":1220,"wires":[["64fa2ace.070df4"]]},{"id":"cc912830.ac5188","type":"function","z":"afaa0885.ad2718","name":"initialize","func":"if (!msg.payload) return;\n\nvar topicParts=\"\";\n\ntry {\n topicParts=msg.topic.split('.');\n} catch (err) {\n node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n}\nvar keyword = topicParts.pop();\n\nif (topicParts.length<3) {\n node.status({fill:\"red\",shape:\"dot\",text:\"msg.topic='object.property' expected\"});\n return;\n}\n\n\n// get or initalize root for global store\nvar currentObject= global.get(topicParts[0],\"file\");\nif (!currentObject) {\n currentObject={};\n global.set(topicParts[0],currentObject,\"file\")\n}\n\n// function to create object for specific topic\ncurrentObject.newObject = function(topic) {\n var topicParts = topic.split('.');\n var keyword=topicParts.pop();\n if (keyword!='uiAdd') return Null\n if (topicParts.length<2) return null;\n var objectPtr=global.get(topicParts[0],\"file\");\n for (var i=1; i<topicParts.length; i++) {\n if (!objectPtr[topicParts[i]]) return null; // object not found\n objectPtr=objectPtr[topicParts[i]];\n }\n if (!objectPtr.list) objectPtr.list=[]; // initialize list if not existing\n objectPtr.list.push({}); // add new object into list\n return objectPtr;\n};\n\n// function to get object for specific topic\ncurrentObject.getObject = function(topic) {\n var topicParts = topic.split('.');\n if (topicParts.length<2) return null;\n var objectPtr=global.get(topicParts[0],\"file\");\n for (var i=1; i<topicParts.length-1; i++) { // ignore the last identifier\n if (!objectPtr[topicParts[i]]) return null; // object not found\n objectPtr=objectPtr[topicParts[i]];\n } \n return objectPtr;\n};\n\n// function to get object for current entry out of list\ncurrentObject.getEntry = function(topic) {\n objectPtr=this.getObject(topic);\n if (objectPtr.uiPointer<objectPtr.list.length){\n return objectPtr.list[objectPtr.uiPointer];\n }\n return null;\n};\n\n// function to delete current entry out of list\ncurrentObject.deleteEntry = function(topic) {\n objectPtr=this.getObject(topic);\n if (objectPtr.uiPointer<objectPtr.list.length){\n var returnObj= objectPtr.list.splice(objectPtr.uiPointer,1);\n if (returnObj) objectPtr.uiPointer=0;\n return returnObj;\n }\n return null;\n};\n\n// (re)build Object Tree\nvar objectRoot= currentObject;\nfor (i=1; i<topicParts.length; i++) {\n if (!currentObject[topicParts[i]]) currentObject[topicParts[i]]={};\n currentObject=currentObject[topicParts[i]];\n}\nif (currentObject.uiPointer===undefined) currentObject.uiPointer=0;\nnode.status({fill:\"green\",shape:\"dot\",text:\"done!\"});\nreturn msg;\n","outputs":1,"noerr":0,"x":260,"y":1100,"wires":[["1273f17e.cacfff"]]},{"id":"ea72c8b7.6b8be8","type":"ui_list","z":"afaa0885.ad2718","group":"4ac97505.03ae4c","name":"days","order":20,"width":"8","height":"7","lineType":"one","actionType":"check","allowHTML":false,"outputs":1,"topic":"mySettings.heating.periods.days","x":610,"y":1460,"wires":[["20d22b21.441424"]]},{"id":"1727a207.b3522e","type":"ui_group","z":"","name":"Zeitabschnitt","tab":"831d491a.c7a7e8","order":3,"disp":true,"width":"8","collapse":false},{"id":"4ac97505.03ae4c","type":"ui_group","z":"","name":"Wochentage","tab":"831d491a.c7a7e8","order":4,"disp":true,"width":"8","collapse":true},{"id":"831d491a.c7a7e8","type":"ui_tab","z":"","name":"Heizung","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
Hope it is usefull for somebody.Chris