Need help with template node

If I offered a solution I didn't understand your target clear enough for sure. For now it seems far different thing and I have no clue what you try to do.

I have created a template node with tabs, and I've integrated forms inside each tab. However, as I continue to add more forms, the code is becoming too large and difficult to manage. My question is:

Is there a way to use multiple template nodes for the forms and somehow make them appear within the tabs? I am considering using an API, teleport, or any other method to separate the code and make it more manageable. The code is getting hard to follow, as I'm losing track of which form belongs to which tab.

If you have any suggestions on how to organize the code more effectively, that would be really helpful.

Thank you!

I think it is the area where low-code world ends and dedicated building starts. Doesn't mean that helping ends but it takes to know much more about the content and data.

Probably a stupid suggestion but would the Layout: Tabs option work instead of having tabs in a template node?

Just an idea here is this button toggle script

<template>
  <div class="d-flex flex-column align-center bg-grey-lighten-4 pa-6">
    <v-btn-toggle
      v-model="toggle"
      color="primary"
      mandatory
    >
      <v-btn icon="mdi-format-align-left" value="left"></v-btn>
      <v-btn icon="mdi-format-align-center" value="center"></v-btn>
      <v-btn icon="mdi-format-align-right" value="right"></v-btn>
      <v-btn icon="mdi-format-align-justify" value="justify"></v-btn>
    </v-btn-toggle>
    <pre class="pt-2">{{ toggle }}</pre>
  </div>
</template>
<script>
  export default {
    data () {
      return {
        toggle: undefined,
      }
    },
  }
</script>

Each button in the group could be used same way as tab is used. So my idea is that toggle could be used to trigger an event witch will get the forms I need similar to teleport, but hopefully that bug won't affect them the same way as tabs. I can style them to look like tabs.

This is what ChatGPT come out with it might trigger an event on out brains :slight_smile:


Plan

  1. Template Nodes for Each Form:

    • Each form will reside in its own template node, making the code modular and easier to maintain.
  2. Event Node for Communication:

    • Use a ui_control or custom events node to manage the display of forms dynamically.
  3. Toggle Button as Navigation:

    • The v-btn-toggle component will send a payload (like form1, form2, etc.) to an event node, which triggers the respective form template.
  4. Dynamic Rendering:

    • Use the ng-if or v-if directive within the ui_template nodes to show or hide forms based on the current selection.

Node-RED Flow Example

1. Template Node: Toggle Buttons

Add a ui_template node for the toggle buttons:

<template>
  <div class="d-flex flex-column align-center bg-grey-lighten-4 pa-6">
    <v-btn-toggle
      v-model="toggle"
      color="primary"
      mandatory
      @change="sendToggleEvent"
    >
      <v-btn icon="mdi-format-align-left" value="form1">Form 1</v-btn>
      <v-btn icon="mdi-format-align-center" value="form2">Form 2</v-btn>
      <v-btn icon="mdi-format-align-right" value="form3">Form 3</v-btn>
      <v-btn icon="mdi-format-align-justify" value="form4">Form 4</v-btn>
    </v-btn-toggle>
  </div>
</template>

<script>
  let node = this;

  export default {
    data() {
      return {
        toggle: "form1", // Default form
      };
    },
    methods: {
      sendToggleEvent() {
        node.send({ payload: this.toggle }); // Send selected form to Node-RED
      },
    },
  };
</script>

2. Template Node: Individual Forms

Create a separate ui_template node for each form.

Form 1 Example:

<div ng-if="msg.payload === 'form1'">
  <p>Form 1 Content</p>
  <form>
    <!-- Form 1 elements here -->
  </form>
</div>

Form 2 Example:

<div ng-if="msg.payload === 'form2'">
  <p>Form 2 Content</p>
  <form>
    <!-- Form 2 elements here -->
  </form>
</div>

Repeat for all forms.


3. Event Flow

  • Input: Connect the toggle button ui_template node to a change event.
  • Routing: Use a switch node to route the toggle value (e.g., form1, form2) to the respective form's template node.
  • Output: Each form template node will dynamically render its content based on the msg.payload.

4. Node-RED Flow Diagram

  1. Toggle Button Node ā†’ Switch Node (checks msg.payload) ā†’ Template Nodes (for individual forms).
  2. For reusability, loop back the toggle button to the same event node to handle new changes.

So something like this then...

[{"id":"3d04b2945b122f5a","type":"ui-template","z":"118077bdc5e1ce7a","group":"9cf83c652cce0c5b","page":"","ui":"","name":"Master","order":1,"width":0,"height":0,"head":"","format":"<template>\n    <div>        \n        <v-btn-toggle v-model=\"form\" color=\"deep-purple-accent-3\" rounded=\"0\" group>\n            <v-btn value=\"form-A\">\n                A\n            </v-btn>\n        \n            <v-btn value=\"form-B\">\n                B\n            </v-btn>\n        \n            <v-btn value=\"form-C\">\n                C\n            </v-btn>\n        \n            <v-btn value=\"form-D\">\n                D\n            </v-btn>\n        </v-btn-toggle>\n        <div class=\"form-master\"></div>\n        <div class=\"form-hidden\"></div>\n    </div>\n</template>\n\n<script>\n    export default {\n        data() {\n            // define variables available component-wide\n            // (in <template> and component functions)\n            return {\n                form: \"form-A\"\n            }\n        },\n        watch: {\n            // watch for any changes of \"count\"\n            form: function () {\n               \n                    this.send({payload: this.form})\n              \n            }\n        },\n        computed: {\n            \n        },\n        methods: {\n            \n        },\n        mounted() {\n            // code here when the component is first loaded\n        },\n        unmounted() {\n            // code here when the component is removed from the Dashboard\n            // i.e. when the user navigates away from the page\n        }\n    }\n</script>\n<style>\n   .form-hidden{\n    display:none;\n   }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":790,"y":460,"wires":[["2a3631722a55272e","b34afd6a42c7fd5f","1b8d70225f9c408f","d7c786a14007ea3b"]]},{"id":"2a3631722a55272e","type":"ui-template","z":"118077bdc5e1ce7a","group":"ceb92482da92350a","page":"","ui":"","name":"Form A","order":4,"width":0,"height":0,"head":"","format":"<template>\n    <Teleport v-if=\"mounted\" :to=\"target\">\n        <div>{{formName}}</div>        \n    </Teleport>\n</template>\n\n<script>\n    export default {\n        data() {           \n            return {               \n                formName:\"form-A\",               \n                mounted:false,\n                target:\"\",\n               \n            }\n        },\n        computed: {        \n            \n        },\n        watch: {\n            msg: function () {\n                if(this.msg?.payload != undefined){\n                    this.target = this.msg.payload == this.formName ? \".form-master\" : \".form-hidden\"\n                }                \n            }\n        },\n        mounted(){            \n            this.target = \".form-hidden\"\n            this.mounted = true            \n        }\n    }\n</script>\n<style>\n    .hidden-template {\n        display: none !important;\n    }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"hidden-template","x":1000,"y":400,"wires":[[]]},{"id":"b34afd6a42c7fd5f","type":"ui-template","z":"118077bdc5e1ce7a","group":"ceb92482da92350a","page":"","ui":"","name":"Form B","order":1,"width":0,"height":0,"head":"","format":"<template>\n    <Teleport v-if=\"mounted\" :to=\"target\">\n        <div>{{formName}}</div>        \n    </Teleport>\n</template>\n\n<script>\n    export default {\n        data() {           \n            return {               \n                formName:\"form-B\",               \n                mounted:false,\n                target:\"\",\n               \n            }\n        },\n        computed: {        \n            \n        },\n        watch: {\n            msg: function () {\n                if(this.msg?.payload != undefined){\n                    this.target = this.msg.payload == this.formName ? \".form-master\" : \".form-hidden\"\n                }                \n            }\n        },\n        mounted(){            \n            this.target = \".form-hidden\"\n            this.mounted = true            \n        }\n    }\n</script>\n<style>\n    .hidden-template {\n        display: none !important;\n    }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"hidden-template","x":1000,"y":440,"wires":[[]]},{"id":"1b8d70225f9c408f","type":"ui-template","z":"118077bdc5e1ce7a","group":"ceb92482da92350a","page":"","ui":"","name":"Form C","order":3,"width":0,"height":0,"head":"","format":"<template>\n    <Teleport v-if=\"mounted\" :to=\"target\">\n        <div>{{formName}}</div>        \n    </Teleport>\n</template>\n\n<script>\n    export default {\n        data() {           \n            return {               \n                formName:\"form-C\",               \n                mounted:false,\n                target:\"\",\n               \n            }\n        },\n        computed: {        \n            \n        },\n        watch: {\n            msg: function () {\n                if(this.msg?.payload != undefined){\n                    this.target = this.msg.payload == this.formName ? \".form-master\" : \".form-hidden\"\n                }                \n            }\n        },\n        mounted(){            \n            this.target = \".form-hidden\"\n            this.mounted = true            \n        }\n    }\n</script>\n<style>\n    .hidden-template {\n        display: none !important;\n    }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"hidden-template","x":1000,"y":480,"wires":[[]]},{"id":"d7c786a14007ea3b","type":"ui-template","z":"118077bdc5e1ce7a","group":"ceb92482da92350a","page":"","ui":"","name":"Form D","order":2,"width":0,"height":0,"head":"","format":"<template>\n    <Teleport v-if=\"mounted\" :to=\"target\">\n        <div>{{formName}}</div>        \n    </Teleport>\n</template>\n\n<script>\n    export default {\n        data() {           \n            return {               \n                formName:\"form-D\",               \n                mounted:false,\n                target:\"\",\n               \n            }\n        },\n        computed: {        \n            \n        },\n        watch: {\n            msg: function () {\n                if(this.msg?.payload != undefined){\n                    this.target = this.msg.payload == this.formName ? \".form-master\" : \".form-hidden\"\n                }                \n            }\n        },\n        mounted(){            \n            this.target = \".form-hidden\"\n            this.mounted = true            \n        }\n    }\n</script>\n<style>\n    .hidden-template {\n        display: none !important;\n    }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"hidden-template","x":1000,"y":520,"wires":[[]]},{"id":"9cf83c652cce0c5b","type":"ui-group","name":"Master","page":"168fe714d5f10b94","width":"6","height":"1","order":2,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"ceb92482da92350a","type":"ui-group","name":"Hidden Forms","page":"168fe714d5f10b94","width":"6","height":"1","order":1,"showTitle":true,"className":"hidden-template","visible":"true","disabled":"false","groupType":"default"},{"id":"168fe714d5f10b94","type":"ui-page","name":"Teleport Form ","ui":"29792df7d7b05e2e","path":"/teleportform","icon":"home","layout":"grid","theme":"24f03c7583353e46","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"29792df7d7b05e2e","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":false,"acceptsClientConfig":[],"showPathInSidebar":false,"showPageTitle":true,"navigationStyle":"default","titleBarStyle":"default"},{"id":"24f03c7583353e46","type":"ui-theme","name":"Default","colors":{"surface":"#ffffff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]
1 Like

My Hero Thank you

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