smurfier
smurfier

Reputation: 25

I can't get my vue component emit to work

I'm new to vue (less than a week) and I'm rewriting a hobby project to get up and going. Decided to try out components and ran into and issue. One of my sub-components emits just fine, but the other one is not received by the parent. The vue-devtools chrome extension tells me that sidenavselect is indeed emitting the close event, but the sidenav v-on:close is not being triggered.

<sidenav v-on:close="sidebar_show = false" v-show="sidebar_show">
    <sidenavbutton @click="draw_board">Start Round</sidenavbutton>
    <sidenavselect v-model="location" :datafield="locations" title="Location"></sidenavselect>
</sidenav>
Vue.component('sidenav', {
    props: ['method'],
    template: `
        <div class="sidenav" v-on:close="handle_close" @click.self="handle_close">
            <div class="contents" v-on:close="handle_close">
                <span class="closebtn" v-on:click="handle_close">&times;</span>
                <slot></slot>
            </div>
        </div>
    `,
    methods: {
        handle_close: function() {
            this.$emit('close');
        }
    }
});

Vue.component('sidenavbutton', {
    template: `
        <button tabindex="-1" @click="handle_click"><slot></slot></button>
    `,
    methods: {
        handle_click: function() {
            this.$emit('click');
            this.$emit('close');
        }
    }
});

Vue.component('sidenavselect', {
    props: ['datafield', 'title', 'value'],
    template: `
        <div class="sidenav-box">
            {{title}}<br>
            <select tabindex="-1" v-bind:value="value" @input="handle_close">
                <option v-for="this_data in datafield" :value="this_data.value">{{this_data.label}}</option>
            </select>
        </div>
    `,
    methods: {
        handle_close: function(event) {
            this.$emit('input', event.target.value);
            this.$emit('close');
        }
    }
});

Upvotes: 1

Views: 379

Answers (2)

smurfier
smurfier

Reputation: 25

The answer to my issue was that the methods attached to the buttons were still closing the sidenav from before I was working with components.

User skirtle was correct in that each component I used needed to have @close on them.

Upvotes: 0

Gander
Gander

Reputation: 1991

Vue.component("sidenav", {
  template: `
        <div class="sidenav" @close="handle_close" @click.self="handle_close">
            <div class="contents" @close="handle_close">
                <span class="closebtn" @click="handle_close">&times;</span>
                <slot></slot>
            </div>
        </div>
    `,
  methods: {
    handle_close: function() {
      this.$emit("close");
    }
  }
});

Vue.component("sidenavbutton", {
  template: `
        <button @click="handle_click"><slot></slot></button>
    `,
  methods: {
    handle_click: function() {
      this.$emit("click");
      this.$emit("close");
    }
  }
});

Vue.component("sidenavselect", {
  props: ["value"],
  template: `
        <div class="sidenav-box">
            <select :value="value" @input="handle_close">
                <option value="1">A</option>
                <option value="2">B</option>
                <option value="3">C</option>
            </select>
        </div>
    `,
  methods: {
    handle_close: function(event) {
      this.$emit("input", event.target.value);
      this.$emit("close");
    }
  }
});

new Vue({
  data() {
    return {
      sidebar_show: true,
      location: 0
    };
  },
  methods: {
    handle_close: function(event) {
      this.sidebar_show = false;
    }
  }
}).$mount("#app");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <sidenav @close="handle_close" v-show="sidebar_show">
    <sidenavbutton @close="handle_close">Start Round</sidenavbutton>
    <sidenavselect @close="handle_close" v-model="location"></sidenavselect>
  </sidenav>
</div>

You want to do too much at once. Take smaller steps. It's easier to catch mistakes.

Upvotes: 1

Related Questions