Hi All
I'll be upfront and say that I got very frustrated with DashBoard2 when it came time to migrate colour pickers.
The template examples on this page look AMAZING and I was really looking forward to using them
The API for them seems to present SO many ways to tweak the layout too.
https://vuetifyjs.com/en/api/v-color-picker/
BUT
That's where the fun stopped and the real pain started
"How to get the selected colours back into Node-red"
Fair play to all those that offered help in different topics, but I did feel a lot like the "stupid friend who didn't know the secret language"
Lot's of great help and pointers, but no real world working examples.
As much as it grieves me, I just turned to Google and asked "node-red dashboard 2 color picker working example"
Which gave me a fairly simply reply
For a working color picker in Node-RED Dashboard 2.0 (FlowFuse), use a standard ui-template node utilizing Vuetify's built-in <v-color-picker>. Because the native template output relies on events, it is best practice to bind the picker to a data property and use a Vue watch to emit color changes back to Node-RED. [1, 2, 3, 4]
Step-by-Step Implementation
- Drag a ui-template node onto your canvas and double-click to edit it.
- Set the Group to your target UI Group and Page.
- Set the Format drop-down to
Vue. - Paste the following code into the Template text box: [1]
html
<template>
<v-card class="mx-auto" max-width="300">
<v-card-text class="d-flex justify-center">
<v-color-picker
v-model="color"
dot-size="25"
mode="hexa"
show-swatches
></v-color-picker>
</v-card-text>
</v-card>
</template>
<script>
export default {
data() {
return {
color: '#FF0000'
}
},
watch: {
color(newVal) {
// Send the color value back to Node-RED on change
this.send({ payload: newVal });
}
}
}
</script>
Use code with caution.
- Click Done and deploy your flow. The picker will send out the updated color code as a
msg.payloadstring immediately as you drag the color wheel or select swatches
Thankfully this works and by changing the Template section, I can adapt to whatever layout I like.
Sadly, the issue still stands that I truly have no idea "WHY IT WORKS"....
I'm not seeking an explanation here, I just wanted to raise the subject that not everyone seeking help has a full working knowledge of required code.
As with anything, if you are helping someone, please give a little more than "This document has everything you need" (which I'm sure it does, IF you understand the basics in the background and the secret language)
Node-red examples
{
"id": "c4e5172f33950768",
"type": "function",
"z": "05226917997ae10c",
"name": "Set Colour into a payload",
"func": "// {\"colour\":\"#0000FF\"}\nvar colour = String(msg.payload) || \"#888888\";\nmsg.payload = {\"colour\":colour};\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 630,
"y": 980,
"wires": [
[
"261133621637a490"
]
]
},
{
"id": "c5f6948951adac32",
"type": "ui-text-input",
"z": "05226917997ae10c",
"group": "48fc19d1161f11e6",
"name": "test colour",
"label": "colour",
"order": 0,
"width": 0,
"height": 0,
"topic": "topic",
"topicType": "msg",
"mode": "color",
"tooltip": "",
"delay": 300,
"passthru": true,
"sendOnDelay": true,
"sendOnBlur": true,
"sendOnEnter": true,
"className": "",
"clearable": false,
"sendOnClear": false,
"icon": "",
"iconPosition": "left",
"iconInnerPosition": "inside",
"x": 250,
"y": 1060,
"wires": [
[
"89ebe423685554b2"
]
]
},
{
"id": "efbd69086911fce8",
"type": "ui-template",
"z": "05226917997ae10c",
"group": "48fc19d1161f11e6",
"page": "",
"ui": "",
"name": "CollourPicker 2",
"order": 2,
"width": 0,
"height": 0,
"head": "",
"format": "<template>\n <div class=\"d-flex justify-space-around\">\n <v-color-picker\n v-model=\"color\"\n :modes=\"['rgba']\"\n ></v-color-picker>\n\n <div class=\"d-flex flex-column\">\n <v-color-picker\n v-model=\"color\"\n v-model:mode=\"mode\"\n ></v-color-picker>\n <v-select\n v-model=\"mode\"\n :items=\"modes\"\n style=\"max-width: 300px\"\n ></v-select>\n </div>\n </div>\n</template>\n<script setup>\n import { ref } from 'vue'\n\n const color = ref('#ff00ff')\n const mode = ref('hsla')\n const modes = ref(['hsla', 'rgba', 'hexa'])\n</script>\n\n<script>\nexport default {\n data() {\n return {\n color: '#FF0000'\n }\n },\n watch: {\n color(newVal) {\n // Send the color value back to Node-RED on change\n this.send({ payload: newVal });\n }\n }\n}\n</script>",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 300,
"y": 1100,
"wires": [
[
"89ebe423685554b2"
]
]
},
{
"id": "52b7b111fb88dd6e",
"type": "ui-template",
"z": "05226917997ae10c",
"group": "48fc19d1161f11e6",
"page": "",
"ui": "",
"name": "CollourPicker simple",
"order": 1,
"width": 0,
"height": 0,
"head": "",
"format": "<template>\n <v-card class=\"mx-auto\" max-width=\"300\">\n <v-card-text class=\"d-flex justify-center\">\n <v-color-picker\n v-model=\"color\"\n dot-size=\"25\"\n mode=\"hexa\"\n show-swatches\n ></v-color-picker>\n </v-card-text>\n </v-card>\n</template>\n\n<script>\nexport default {\n data() {\n return {\n color: '#FF0000'\n }\n },\n watch: {\n color(newVal) {\n // Send the color value back to Node-RED on change\n this.send({ payload: newVal });\n }\n }\n}\n</script>",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 320,
"y": 1140,
"wires": [
[
"89ebe423685554b2"
]
]
},
{
"id": "81d2f0e735d7b6da",
"type": "ui-template",
"z": "05226917997ae10c",
"group": "48fc19d1161f11e6",
"page": "",
"ui": "",
"name": "Brightness",
"order": 3,
"width": 0,
"height": 0,
"head": "",
"format": "<template>\n <div class=\"text-center\">\n <v-rating v-model=\"rating\" active-color=\"blue\" color=\"orange-lighten-1\" length=\"10\">\n </v-rating>\n </div>\n</template>\n<script>\n export default {\n data: () => ({ rating: 3 }),\n watch: {\n rating: function () {\n this.send({payload: this.rating})\n }\n }\n }\n</script>",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 330,
"y": 1240,
"wires": [
[
"3e876e2b77f80b0f"
]
]
},
{
"id": "3e876e2b77f80b0f",
"type": "debug",
"z": "05226917997ae10c",
"name": "DashBoard 2 Example vuetifyjs templates",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 820,
"y": 1140,
"wires": []
},
{
"id": "89ebe423685554b2",
"type": "junction",
"z": "05226917997ae10c",
"x": 460,
"y": 1120,
"wires": [
[
"3e876e2b77f80b0f",
"c4e5172f33950768"
]
]
},
{
"id": "48fc19d1161f11e6",
"type": "ui-group",
"name": "Test",
"page": "19eb6d108e9275e2",
"width": "20",
"height": "13",
"order": 1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "19eb6d108e9275e2",
"type": "ui-page",
"name": "Examples",
"ui": "485a6940f66045af",
"path": "/examples",
"icon": "",
"layout": "tabs",
"theme": "a965ccfef139317a",
"order": 2,
"className": "",
"visible": true,
"disabled": "false"
},
{
"id": "485a6940f66045af",
"type": "ui-base",
"name": "Dashboard",
"path": "/dashboard",
"appIcon": "",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-control"
],
"showPathInSidebar": false,
"headerContent": "page",
"navigationStyle": "default",
"titleBarStyle": "default",
"showReconnectNotification": true,
"notificationDisplayTime": 1,
"showDisconnectNotification": true,
"allowInstall": true
},
{
"id": "a965ccfef139317a",
"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"
}
},
{
"id": "153dad6ce93f598c",
"type": "global-config",
"env": [],
"modules": {
"@flowfuse/node-red-dashboard": "1.30.2"
}
}
]
Thanks to @Steve-Mcl for the extra tips
I've updated this Flow to add the Text entry box as a colour picker





