Setting the src attribute in an img tag (ui-template node) by a variable from inside the ui-template

Hi there,
I'going to build a clickable icon/picture in dashboard 2. It should have 2 pictures, toggled by the click. f.ex. bulb-on.png and bulb-off.png.

How can I set the src of the img tag with a variable of my ui-template - node?

I tried setting an id to the img tag, getting the document id and setting the id.src - without success.

Here is an example code:

[
    {
        "id": "ad232f5935af2994",
        "type": "ui-template",
        "z": "f4e5a1a4a9bb3cc8",
        "group": "91121ba376b2577b",
        "page": "",
        "ui": "",
        "name": "Mein Button",
        "order": 4,
        "width": 0,
        "height": 0,
        "head": "",
        "format": "<template>\n    <div class=\"button\" id=\"divImage\" @click=\"toggleImage()\">\n        <img src=\"\" alt=\"Klickbare Grafik\" id=\"buttonImage\"/>\n        <p id=\"buttonText\">fridge</ p>\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                images: {\n                    image1: '/fridge_green.png', // Ersetzen Sie dies mit der URL Ihres ersten Bildes\n                    image2: '/fridge_red.png'    // Ersetzen Sie dies mit der URL Ihres zweiten Bildes\n                };\n                image = document.getElementById(\"buttonImage\");\n                image.src='/fridge.png';\n            }\n        },\n      \n        watch: {\n            // watch for any changes of \"msg\"\n            msg: function () {\n                if (this.msg.payload && (this.msg.payload === this.images.image1 || this.msg.payload === this.images.image2)) {\n                    this.currentImage = this.msg.payload;\n                }\n            }\n        },\n        computed: {\n            // automatically compute this variable\n            // whenever VueJS deems appropriate\n        },\n        methods: {\n            // expose a method to our <template> and Vue Application\n            toggleImage: function () {\n                this.currentImage = (this.currentImage === this.images.image1) ? this.images.image2 : this.images.image1;\n                this.send({ payload: this.currentImage });\n            }\n        },\n\n        mounted() {\n            // code here when the component is first loaded\n                this.currentImage = this.images.image1;\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\n</script>\n\n<style>\n    .button {\n        width: 128px;\n        height: 128px;\n\n    }\n</style>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 430,
        "y": 580,
        "wires": [
            [
                "877e92118f317e5a"
            ]
        ]
    },
    {
        "id": "91121ba376b2577b",
        "type": "ui-group",
        "name": "Seuchlicht",
        "page": "c6ed8176203ca17b",
        "width": 6,
        "height": 1,
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "c6ed8176203ca17b",
        "type": "ui-page",
        "name": "Logger",
        "ui": "6ffb10ff06c355be",
        "path": "/page2",
        "icon": "home",
        "layout": "grid",
        "theme": "6c7fce75833af206",
        "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": 2,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "6ffb10ff06c355be",
        "type": "ui-base",
        "name": "My 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
    },
    {
        "id": "6c7fce75833af206",
        "type": "ui-theme",
        "name": "Default Theme",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094ce",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    }
]

I appreciate your help.

Regards,
Zephyr

Hello ..

the way i would approach this is by creating a Vue boolean variable that represents the bulb status bulbStatus and based on its true or false value show the correct image by using v-bind on the :src of the img.

This can be achieved by using inline ternary operator
:src="bulbStatus ? '/fridge_green.png' : '/fridge_red.png'"

If bulbStatus is true the img source will be /fridge_green.png otherwise /fridge_red.png'

The sample code also sends a msg back to node-red of the current status
this.send({ payload: { bulbStatus: this.bulbStatus} });

<template>
    <div class="button" id="divImage" @click="toggleImage()">
        <v-icon :color="bulbStatus ? 'orange' : 'black'" icon="mdi-lightbulb" size="100px"></v-icon>
        <img :src="bulbStatus ? '/fridge_green.png' : '/fridge_red.png'" alt="Klickbare Grafik" id="buttonImage"/>
        <!-- <p id="buttonText">fridge</p> -->
    </div>
</template>

<script>
    export default {
        data() {
            // define variables available component-wide
            // (in <template> and component functions)
            return {
                bulbStatus: true // fridge ON or OFF
            }
        },
      
        watch: {
            // watch for any changes of "msg"
            msg: function (msg) {
                if (msg.payload && msg.payload.bulbStatus) {
                    this.bulbStatus = msg.payload.bulbStatus;
                }
            }
        },
        computed: {
            // automatically compute this variable
            // whenever VueJS deems appropriate
        },
        methods: {
            // expose a method to our <template> and Vue Application
            toggleImage: function () {
                this.bulbStatus = !this.bulbStatus  // toggle bulbStatus
                console.log("bulbStatus", this.bulbStatus)
                this.send({ payload: { bulbStatus: this.bulbStatus} });
            }
        },

        mounted() {
            // code here when the component is first loaded
            // code to request current actual bulb status this.send({payload : "bulbCurrentStatus"})
        },
        unmounted() {
            // code here when the component is removed from the Dashboard
            // i.e. when the user navigates away from the page
        }
    }

</script>

<style>
    .button {
        width: 128px;
        height: 128px;

    }
</style>

* Did a test with a v-icon and its color since i dont have your images

1 Like

Hi Andy,
thank you very much,
great idea! The last weeks, I've spent many hours getting familiar with vue or dashboard-2. Sometimes with success, sometimes, hmmm, with some "nice results" :grinning:

I've tested your code, it works like a charm.
Now I can step further in converting my 1,5Mbytes flow-file from dashboard 1 to dashboard 2.

[
    {
        "id": "fb1784fe33113bdc",
        "type": "inject",
        "z": "f4e5a1a4a9bb3cc8",
        "name": "Set Off",
        "props": [
            {
                "p": "payload.bulbStatus",
                "v": "false",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 130,
        "y": 460,
        "wires": [
            [
                "b14297362818da41"
            ]
        ]
    },
    {
        "id": "68fcf6f4a0223cf9",
        "type": "inject",
        "z": "f4e5a1a4a9bb3cc8",
        "name": "Set On",
        "props": [
            {
                "p": "payload.bulbStatus",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 130,
        "y": 500,
        "wires": [
            [
                "b14297362818da41"
            ]
        ]
    },
    {
        "id": "877e92118f317e5a",
        "type": "debug",
        "z": "f4e5a1a4a9bb3cc8",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 520,
        "y": 480,
        "wires": []
    },
    {
        "id": "b14297362818da41",
        "type": "ui-template",
        "z": "f4e5a1a4a9bb3cc8",
        "group": "91121ba376b2577b",
        "page": "",
        "ui": "",
        "name": "universal button",
        "order": 1,
        "width": 0,
        "height": 0,
        "head": "",
        "format": "<template>\n    <div class=\"button\" id=\"divImage\" @click=\"toggleImage()\">\n        <!-- <v-icon :color=\"bulbStatus ? 'orange' : 'black'\" icon=\"mdi-lightbulb\" size=\"100px\"></v-icon> -->\n        <img :src=\"bulbStatus ? '/fridge_green.png' : '/fridge_red.png'\" alt=\"Klickbare Grafik\" id=\"buttonImage\"/>\n        <!-- <p id=\"buttonText\">fridge</p> -->\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                bulbStatus: true // fridge ON or OFF\n            }\n        },\n      \n        watch: {\n            // watch for any changes of \"msg\"\n            msg: function (msg) {\n                if ((msg.payload && msg.payload.bulbStatus)||(msg.payload && !msg.payload.bulbStatus)) {\n                    this.bulbStatus = msg.payload.bulbStatus;\n                }\n            }\n        },\n        computed: {\n            // automatically compute this variable\n            // whenever VueJS deems appropriate\n        },\n        methods: {\n            // expose a method to our <template> and Vue Application\n            toggleImage: function () {\n                this.bulbStatus = !this.bulbStatus  // toggle bulbStatus\n                console.log(\"bulbStatus\", this.bulbStatus)\n                this.send({ payload: { bulbStatus: this.bulbStatus} });\n            }\n        },\n\n        mounted() {\n            // code here when the component is first loaded\n            // code to request current actual bulb status this.send({payload : \"bulbCurrentStatus\"})\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\n</script>\n\n<style>\n    .button {\n        width: 128px;\n        height: 128px;\n\n    }\n</style>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 340,
        "y": 480,
        "wires": [
            [
                "877e92118f317e5a"
            ]
        ]
    },
    {
        "id": "91121ba376b2577b",
        "type": "ui-group",
        "name": "Seuchlicht",
        "page": "c6ed8176203ca17b",
        "width": 6,
        "height": 1,
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "c6ed8176203ca17b",
        "type": "ui-page",
        "name": "Logger",
        "ui": "6ffb10ff06c355be",
        "path": "/page2",
        "icon": "home",
        "layout": "grid",
        "theme": "6c7fce75833af206",
        "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": 2,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "6ffb10ff06c355be",
        "type": "ui-base",
        "name": "My 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
    },
    {
        "id": "6c7fce75833af206",
        "type": "ui-theme",
        "name": "Default Theme",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094ce",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    }
]


Now I can set the icon of the button by msg.payload.bulbStatus and send the button-clicks to the rest of the flow.... Great, my touch monitor will love that.

Thank you,
t'il next time.

Jochen

1 Like