@BartButenaers Don't mess with strings just like that
Also don't take away option to deal with indexes. Some of us do like math and numbers
TEMPLATE
<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>
</div>
</template>
<script>
export default {
data() {
return {
//define me here
label:"Multistate Prototype",
options:[
{label:"",value:"on",icon:"mdi-antenna",color:"green"},// label can be empty
{value:"off", icon:"mdi-basketball",color:"red"},//can omit the label
{label:"Auto",value:"auto", color:"blue",icon:"mdi-car-wrench"},// can omit the icon
{label:"Manual", value:"manual", color:"orange",icon:"mdi-car-shift-pattern"}// 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:"outlined",
// 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>
CSS
.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;
}
EDIT - made label also optional.