How to change Clicked_Button appearance

[{"id":"f4072154f91a999d","type":"inject","z":"0717a61e1ce5f6fe","name":"","props":[{"p":"payload"},{"p":"mc","v":"[\"m%\",\"m00\",\"m01\",\"m02\",\"m03\",\"m04\"]","vt":"json"},{"p":"nick","v":"[\"All\",\"Machine-00\",\"Machine-01\",\"Machine-02\",\"Machine-03\",\"Machine-04\"]","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{}","payloadType":"json","x":2450,"y":1340,"wires":[["07d40ad4ca6058ec"]]},{"id":"07d40ad4ca6058ec","type":"ui-template","z":"0717a61e1ce5f6fe","group":"42242bd3b1fe7e25","name":"M/C Buttons","order":1,"width":0,"height":0,"head":"","format":"<style>\n  .grid-container {    display: flex;    gap: 2px;  }\n  .grid-button {    flex-grow: 1;    padding: 4px;    \n  text-align: center;    font-size: 12px;    font-weight: bold;    \n  color: #4b3d2b;    border: 1px solid #c9b49b;    border-radius: 4px;    \n  cursor: pointer;    background-image: linear-gradient(to bottom, silver, grey);\n  box-shadow: 0 2px 0 0 #d3bca3, 0 3px 0 0 #b39b85, 0 4px 0 0 #947e6a;    \n  transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out;  }\n  .grid-button:hover {    background-image: linear-gradient(to bottom, #d8c7b4, #c9b49b);  }\n  .grid-button:active {    transform: translateY(2px);    box-shadow: 0 0 0 0 #d3bca3, 0 0 0 0 #b39b85, 0 2px 0 0 #947e6a;  }\n  .grid-button.active {    color: #fff;    background-color: #6a9557;    background-image: linear-gradient(to bottom, #82b270, #4d7a3d);    box-shadow: 0 2px 0 0 #4d7a3d, 0 3px 0 0 #3a602c, 0 4px 0 0 #2b451f;  }\n\n</style>\n\n<div class=\"grid-container\">\n  <button \n    v-for=\"(nick, index) in msg.nick\" \n    :key=\"index\"\n    class=\"grid-button\"\n    :class=\"{ active: nick === active_nick }\"\n    @click=\"send({payload: msg.mc[index]})\">\n    {{ nick }}\n  </button>\n</div>\n\n<script>\n    // This is the standard way to handle data and events in a Node-RED ui-template\n    // It's much simpler than a full Vue component setup\n    // The `msg` object is automatically available in the template's scope\n    \n    // We can use a property to track the active button\n    // This variable will be part of the `scope` object\n    var active_nick = null;\n\n    // This function will be called on button click\n    function sendPayload(payload) {\n        // Update the active button state\n        active_nick = payload;\n        // Send the payload out of the node\n        this.send({ payload: payload });\n    }\n</script>","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":2610,"y":1340,"wires":[["2acb23b1618f265b","43a34650e6f12aaf"]]},{"id":"43a34650e6f12aaf","type":"debug","z":"0717a61e1ce5f6fe","name":"Debug-1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2770,"y":1340,"wires":[]},{"id":"42242bd3b1fe7e25","type":"ui-group","name":"DT","page":"42b40ffce547bedc","width":"15","height":"1","order":3,"showTitle":false,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"42b40ffce547bedc","type":"ui-page","name":"ODT","ui":"0aa5ac292a3ec726","path":"/odt","icon":"home","layout":"grid","theme":"71df790af7efd885","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":"14"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"0aa5ac292a3ec726","type":"ui-base","name":"DEL MONTE HOSUR","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control","ui-form","ui-text-input","ui-number-input","ui-file-input","ui-button","ui-button-group","ui-radio-group","ui-slider","ui-switch","ui-text","ui-table","ui-chart","ui-gauge","ui-markdown","ui-template","ui-tabulator"],"showPathInSidebar":true,"navigationStyle":"temporary","titleBarStyle":"default"},{"id":"71df790af7efd885","type":"ui-theme","name":"BT Dark blue","colors":{"surface":"#004b96","primary":"#c8c8c8","bgPage":"#19232d","groupBg":"#000000","groupOutline":"#00e119"},"sizes":{"density":"compact","pagePadding":"1px","groupGap":"1px","groupBorderRadius":"1px","widgetGap":"1px"}}]

I was able to get few buttons on the dashboard-2, the click function works as well thanks to Google Gemini.
I asked it to modify the code so that the last clicked button appears differently, may be like inverse, so that i know what was the last pressed button, it is giving changes in code, but when i deploy the change, either nothing happens when i click (no output in debug node) or the buttons disappear altogether, we have been going around in these circles for nearly 2 hours, no breakthrough, the attached code works perfectly except that the last pressed button is difficult to identify.

In a more vue template style:

<template>
  <div class="grid-container">
    <button
      v-for="(nick, index) in msg.nick"
      :key="index"
      class="grid-button"
      :class="{ active: nick === active_nick }"
      @click="selectTab(nick, msg.mc[index])">
      {{ nick }}
    </button>
  </div>
</template>

<script>
  export default {
  data() {
    return {
      active_nick: null
    };
  },
  methods: { 
    selectTab(nick, payload) {
      this.active_nick = nick;
      this.send({ payload });
    }
  }
}
</script>

<style>
  /* Layout container */
  .grid-container {
    display: flex;
    gap: 4px;
    padding: 6px;
    background-color: #f4f4f4;
    border-radius: 6px;
  }

  /* Inactive (flat gray) */
  .grid-button {
    flex-grow: 1;
    padding: 8px 12px;
    text-align: center;
    font-size: 13px;
    font-weight: 600;
    color: #444;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    background-color: #e0e0e0;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;
  }

  /* Hover for inactive */
  .grid-button:hover {
    background-color: #d5d5d5;
  }

  /* Active (flat blue) */
  .grid-button.active {
    color: #fff;
    background-color: #1d6fc1;
  }

  /* Hover for active */
  .grid-button.active:hover {
    background-color: #1660aa;
  }
</style>
1 Like

Bind the button color to a variable in your data. For example:

<template>
    <div>
        <v-btn :color="btnColors[0]" @click="onClick(1)">Button 1</v-btn>&nbsp
        <v-btn :color="btnColors[1]" @click="onClick(2)">Button 2</v-btn>&nbsp
        <v-btn :color="btnColors[2]" @click="onClick(3)">Button 3</v-btn>
    </div>
</template>
<script type="text/javascript">
export default {
data () {
    return {
      btnColors:["blue","blue","blue"]
    }
},
methods: {
    onClick: function(index) {
        for (let i = 0 ; i < this.btnColors.length ; i++)
          this.btnColors[i] = "blue";
        this.btnColors[index-1] = "red";

        const msg = {payload:"Button "+index+" clicked"};
        this.send(msg);
    }
} 
} 
</script>
1 Like

Nice...it works.

1 Like

for fixed buttons (hard coded in template) i do have some similar working. but my button labels and output from those clicks are coming from an array, not sure how to adapt this.
@bakman2 solution fits in my existing template.