vue.jsvuejs3publish-subscribeeventemitter

mitt event bus with combobox usage in VueJS 3


I have configured mitt as a global event bus in my main.js:

import { createApp } from "vue";
import App from './App.vue'
import mitt from "mitt";
const emitter = mitt();
const app = createApp(App);
app.config.globalProperties.emitter = emitter;
app.mount("#app");

And I'm publishing an event using the event-bus from the child component as follows:

<template>
    <div class= "combobox">
        <label for={{selector_name}}>
            <p>{{ selector_title }}</p>
        </label>
        <select :name="selector_name"  :id="selector_id" :disabled="disabled" @change="onChange">
            <option v-for="(opt, index) in selector_options" :key="`opt ${index}`">
            {{ opt }}
            </option>
        </select>
    </div>
</template>

<script>

export default {
    name: 'ComboBox',
    data() { 
        return {
            disabled: false,
        };
    },
    props: {
        selector_title: {
            type: String,
            required: true
        },
        selector_name: {
            type: String,
            required: true
        },
        selector_id: {
            type: String,
            default: "combobox"
        },
        selector_options: {
            type: Array,
            required: true
        },
    },
    methods: {
        onChange(event){
            this.emitter.emit('lock-combobox', { id: this.selector_id });
        },
    },
}
</script>

Then I try to subscribe to the event in the parent component as follows:

<template>
<div id="controls" class="param">
    <div class="control" id="combobox1">
        <ComboBox
        selector_title = "Pattern"
        selector_name = "pattern"
        :selector_options="['complex', 'simple']"
        selector_id="combo1"
        ref="combo1"
        />
    </div>
    <div class="control" id="combobox2">
        <ComboBox
        selector_title = "Hand"
        selector_name = "pattern"
        :selector_options="['Left', 'Right']"
        selector_id="combo2"
        ref="combo2"
        />
    </div>
    <div class="control" id="speedslider">
        <SpeedSlider/>
    </div>
    <div class="control" id="startstop">
        <StartStopButton/>
    </div>
    <div class = control id="emergency">
        <Emergency/>
    </div>
</div>
</template>

<script>
import ComboBox from '../components/ComboBox.vue';

export default {
    name: "Controls",
    components: {
        ComboBox,
    },
    created() {
        this.emitter.on('lock-combobox', (event) => {
            this.$refs.event.id.disabled = true;
        });
    },
}
</script>

But whenever I change the option in the Combobox, I get an error:

Uncaught TypeError: undefined has no properties

Can you please tell me how can I solve that? thanks in advance.


Solution

  • Thanks to @bassxzero suggestions the solution:

    child

    <template>
      <div class="combobox">
        <label for="{{selector_name}}">
          <p>{{ selector_title }}</p>
        </label>
        <select
          :name="selector_name"
          :id="selector_id"
          :disabled="disabled"
          @change="lockCombo"
          v-if="!option"
        >
          <option selected value disabled>--select--</option>
          <option v-for="(opt, index) in selector_options" :key="`opt ${index}`">
            {{ opt }}
          </option>
        </select>
        <select :name="selector_name" :id="selector_id" disabled="true" v-else>
          <option selected value disabled>{{ option }}</option>
        </select>
      </div>
    </template>
    
    <script>
    import { store } from "../js/store.js";
    
    export default {
      name: "ComboBox",
      data() {
        return {
          disabled: false,
        };
      },
      props: {
        selector_title: {
          type: String,
          required: true,
        },
        selector_name: {
          type: String,
          required: true,
        },
        selector_id: {
          type: String,
          default: "combobox",
        },
        selector_options: {
          type: Array,
          required: true,
        },
        option: {
          type: String,
          //required: true
        },
      },
      methods: {
        lockCombo(event) {
          this.emitter.emit("lock-combobox", {
            id: this.selector_id,
            value: event.target.value,
          });
          const log = {
            time_stamp: new Date().toISOString(),
            message: "ComboBox Choice [" + event.target.value + "] Was selected!",
            color: "orange",
            name: store.logs.length,
          };
          store.logs.push(log);
        },
      },
    };
    </script>
    

    Parent

    created() {
            this.emitter.on('lock-combobox', (event) => {
                if (event.id === "combo1") {
                    this.$refs.combo1.disabled = true;
                    store.pattern = event.value;
                }
                else if (event.id === "combo2") {
                    this.$refs.combo2.disabled = true;
                    store.arm = event.value;
                }
            });
            this.emitter.off('lock-combobox', (event) => {
                if (event.id === "combo1") {
                    this.$refs.combo1.disabled = true;
                    store.pattern = event.value;
                }
                else if (event.id === "combo2") {
                    this.$refs.combo2.disabled = true;
                    store.arm = event.value;
                }
            });
    }