# DB2 multi state switch revisited

**URL:** <https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084>\
**Category:** General\
**Tags:** dashboard-2\
**Created:** [18 September 2024 20:52 UTC](https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084 "2024-09-18T20:52:47Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![gerry](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gerry/32/21604_2.png) [@gerry](https://discourse.nodered.org/u/gerry)\
**Post date:** [18 September 2024 20:52 UTC](https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084/1 "2024-09-18T20:52:47Z")

</div>

@BartButenaers and @hotNipi posted some multi state switch code and rather than flog that thread I opened a new one. Modified the code somewhat, consolidated it really but what I would like to do is make it multi line if possible.

```auto
<template>
    <div class="mss-wrapper">
        <v-chip variant="text">
            {{label}}
        </v-chip>
        <v-btn-toggle mandatory divided rounded="xl" :variant="variant" :color="selectedColor" v-model="selection">
            <v-btn v-for="(option, index) in options" :key='index' :class="option.label ? '' : 'icon-only'">
                <template v-if="option.icon" v-slot:prepend >
                    <v-icon size="x-large"> {{option.icon}} </v-icon>
                </template>
                {{option.label}}
            </v-btn>        
        </v-btn-toggle>
        <v-btn-toggle mandatory divided rounded="xl" :variant="variant" :color="selectedColor" v-model="selection">
            <v-btn v-for="(option, index) in options" :key='index' :class="option.label ? '' : 'icon-only'">
                <template v-if="option.icon" v-slot:prepend>
                    <v-icon size="x-large"> {{option.icon}} </v-icon>
                </template>
                    {{option.label}}
            </v-btn>
        </v-btn-toggle>
            <v-btn-toggle mandatory divided rounded="xl" :variant="variant" :color="selectedColor" v-model="selection">
                <v-btn v-for="(option, index) in options" :key='index' :class="option.label ? '' : 'icon-only'">
                    <template v-if="option.icon" v-slot:prepend>
                            <v-icon size="x-large"> {{option.icon}} </v-icon>
                    </template>
                        {{option.label}}
            </v-btn>
        </v-btn-toggle>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                //define me here
                label:"",                
                options:[
                     
                    {label:"Timer 1",value:"off"},// can omit the icon
                    {label:"Reset", value:"reset", color:"blue",}// can omit color - defaults to theme color
                ],
                // "outlined" (if the site bg is white or very light)"
                // "default" (if the site bg is dark)"
                // ("text" or "plain" also available but requires some styling)
                look:"default",              
                
                // no need to change those
                selection: null,
                changeByInput:false, // in case of input - render but don't send the msg out
               
            }
        },
      
        watch: {
            msg: function(){        
                if(this.msg.payload != undefined){
                    if(typeof this.msg.payload === "number"){                   
                        if(this.isValidIndex(this.msg.payload)){
                            this.changeByInput = true
                            this.selection = this.msg.payload
                        }                        
                    }
                    else if(typeof this.msg.payload === "string"){
                        if(this.isValidValue(this.msg.payload)){
                            this.changeByInput = true
                            this.selection = this.findOptionIndexByValue(this.msg.payload) // may be null but quarded
                        }
                    }
                    
                }
            },
            selection:function(){                
                if(this.changeByInput == true){
                    this.changeByInput = false
                }
                else{
                    this.send(this.getOutputMessage())
                }
            }
        },

        methods: {
            isValidIndex: function (idx){
                if(idx < 0){
                    return false
                }
                if(idx >= this.options.length){
                    return false
                }
                return true                 
            },
            isValidValue:function (val){
                console.log('validate value',val)
                if(val == null){
                    return false
                }
                if(val == undefined){
                    return false
                }
                if(val == ""){
                    return false
                }
                if(this.options.findIndex(option => option.value === val ) == -1){
                    return false
                }
                return true

            },
            findOptionByValue:function(val){
                let opt = this.options.find(option => option.value === val)
                if(opt){
                    return opt
                }
                return null
            },
            findOptionIndexByValue:function(val){
                let idx = this.options.findIndex(option => option.value === val)                
                if(idx != -1){
                    return idx
                }
                return null
            },
            getOutputMessage:function(){                
                return {payload:this.options[this.selection].value,topic:'multistate'}                
            }
        },
        
        computed: {            
            selectedColor:function(){
                if(this.selection == null){
                    return ""
                }
                return this.options[this.selection].color ?? "rgb(var(--v-theme-primary))"
            },
            variant:function(){
                return this.look == "default" ? null : this.look
            }
        }
    }
</script>

<style>

.mss-wrapper {
    display:grid;
    grid-template-columns:1fr 1fr;
    align-items:center;
}
.mss-wrapper .v-chip__content{
    white-space:normal;
}
.mss-wrapper .v-btn-group{        
    width:max-content; 
    border-color:rgba(var(--v-border-color),.3); 
}
.mss-wrapper .v-btn--variant-elevated, .mss-wrapper .v-btn--variant-outlined{    
   color:#cccccc;
}
.mss-wrapper .icon-only .v-btn__prepend{
    margin-inline:0;
}

</style>

```

played with this quite a bit and found numerous ways to break it but never got the separate line or separate switches figured out. Would like to have different switches on lines 2 and 3. Is this even possible?  
Thanks

---

<div class="post-metadata">

**Author:** ![gerry](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gerry/32/21604_2.png) [@gerry](https://discourse.nodered.org/u/gerry)\
**Post date:** [19 September 2024 01:29 UTC](https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084/2 "2024-09-19T01:29:31Z")

</div>

well, I got to here

```auto
<template>
    <div class="mss-wrapper">
        <v-chip variant="text">
            {{ label }}
        </v-chip>
        <v-btn-toggle mandatory divided rounded="xl" :variant="variant" :color="selectedColor" v-model="selection">
            <v-btn v-for="(option, index) in options" :key="index" :class="option.label ? '' : 'icon-only'">
                <template v-if="option.icon" v-slot:prepend>
                    <v-icon size="x-large">{{ option.icon }}</v-icon>
                </template>
                {{ option.label }} <!-- Correct usage of option.label -->
            </v-btn>
        </v-btn-toggle>
    </div>

    <div class="mss-wrapper">
        <v-chip variant="text">
            {{ label }}
        </v-chip>
        <v-btn-toggle mandatory divided rounded="xl" :variant="variant" :color="selectedColor" v-model="selection">
            <v-btn v-for="(option, index) in options" :key="index" :class="option.label ? '' : 'icon-only'">
                <template v-if="option.icon" v-slot:prepend>
                    <v-icon size="x-large">{{ option.icon }}</v-icon>
                </template>
                {{ option.label }}
                <!-- Correct usage of option.label -->
            </v-btn>
        </v-btn-toggle>
    </div>
    
</template>

<script>
export default {
    data() {
        return {
            label: "Select an Action",
            options: [
                { label: "Start", value: "start", icon: "mdi-timer",color:"red"},
                { label: "Pause", value: "pause", icon: "mdi-pause",color:"blue" },
                { label: "Reset", value: "reset", icon: "mdi-stop-circle",color:"grey" },
            ],
            options: [
                { label: "Start Timer", value: "start", icon: "mdi-timer",color:"green" },
                { label: "Pause Timer", value: "pause", icon: "mdi-pause",color:"brown" },
                { label: "Reset Timer", value: "reset", icon: "mdi-stop-circle",color:"yellow" },
            ],
            look: "default",
            selection: null,
            changeByInput: false,
        };
    },

    watch: {
        msg: function() {
            if (this.msg?.payload !== undefined) {
                this.changeByInput = true;

                if (typeof this.msg.payload === "number" && this.isValidIndex(this.msg.payload)) {
                    this.selection = this.msg.payload;
                } else if (typeof this.msg.payload === "string" && this.isValidValue(this.msg.payload)) {
                    this.selection = this.findOptionIndexByValue(this.msg.payload);
                }
            }
        },
        selection: function() {
            if (!this.changeByInput) {
                this.send(this.getOutputMessage());
            }
            this.changeByInput = false;
        }
    },

    methods: {
        isValidIndex(idx) {
            return idx >= 0 && idx < this.options.length;
        },
        isValidValue(val) {
            return val != null && this.options.some(option => option.value === val);
        },
        findOptionIndexByValue(val) {
            return this.options.findIndex(option => option.value === val) || null;
        },
        getOutputMessage() {
            return { payload: this.options[this.selection]?.value, topic: 'multistate' };
        }
    },

    computed: {
        selectedColor() {
            return this.selection !== null ? (this.options[this.selection].color || "rgb(var(--v-theme-primary))") : "";
        },
        variant() {
            return this.look === "default" ? null : this.look;
        }
    }
};
</script>

<style>
.mss-wrapper {
    display: grid;
    grid-template-columns: 1fr;
    align-items: center;
}
.mss-wrapper .v-chip__content {
    white-space: normal;
}
.mss-wrapper .v-btn-group {
    width: max-content; 
    border-color: rgba(var(--v-border-color), .3); 
}
.mss-wrapper .v-btn--variant-elevated,
.mss-wrapper .v-btn--variant-outlined {    
    color: #cccccc;
}
.mss-wrapper .icon-only .v-btn__prepend {
    margin-inline: 0;
}
</style>

```

but still not right, but closer

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [19 September 2024 05:32 UTC](https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084/3 "2024-09-19T05:32:04Z")

</div>

> [@gerry](#):
>
> @BartButenaers and @hotNipi posted some multi state switch code

Hi @gerry,  
I will post the [link](https://discourse.nodered.org/t/dashboard-2-multi-state-switch/85168/16) here for completeness. After we had that discussion at the time being it was decided that the multistate switch should become a core node: the [ui-button-group](https://dashboard.flowfuse.com/nodes/widgets/ui-button-group.html) node was born.

Last weekend I migrated my own dashboard finally to D2. And now I use that button group node as a replacement for all my old ui-multistate-switch nodes.

Instead of changing hotnipi's sample code, I would appreciate if you could try to do your changes on the ui-button-group node instead. You can find the frontend code [here](https://github.com/FlowFuse/node-red-dashboard/blob/main/ui/src/widgets/ui-button-group/UIButtonGroup.vue). That is the only way to improve our core ui nodes. And I assume Joe doesn't mind to get some help from the community...

About your multiline question: since CSS isn't my best friend, I am afraid I need to pass that question on to others reading this.

Good luck!  
Bart

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [18 December 2024 05:32 UTC](https://discourse.nodered.org/t/db2-multi-state-switch-revisited/91084/4 "2024-12-18T05:32:47Z")

</div>

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