Dimitar Ivanov
Dimitar Ivanov

Reputation: 21

""TypeError: Cannot read property '$emit' of undefined vue

I want to emit event from "home" component to "about" component. But it throws this exception-"TypeError: Cannot read property '$emit' of undefined".

This is my "main.js"

import Vue from "vue";
import App from "./App.vue";
import router from "./router";

export const bus = new Vue();
Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

This is my "Home" component.

<template>
  <div class="home">
    <input
      v-model="text"
      class="text-input"
      placeholder="Add text to your child component"
    />
    <button @click="sendmsg" class="btn-add">Add message</button>
  </div>
</template>

<script>
import { bus } from "../main";

export default {
  name: "home",
  data() {
    return {
      text: "",
    };
  },
  methods: {
    sendmsg() {
      bus.$emit("msg", this.text);
      this.text = "";
    }
  }
};
</script>

And this "About" component

<template>
  <div class="about"></div>
</template>

<script>
import { bus } from "../main";
export default {
  name: "about",
  created() {
    bus.$on("message", (data) => {
      console.log(data);
    });
  }
};
</script>

Upvotes: 1

Views: 3815

Answers (2)

Dimitar Ivanov
Dimitar Ivanov

Reputation: 21

It's working, but whem the components have their own view it's stop working.

App.vue

<template>
  <div class="app">
    <router-link to="/"> HOME</router-link>
    <router-link to="/about"> About</router-link>
    <router-view />
  </div>
</template>

<style lang="scss">
.app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  align-items: center;
  .btn-add {
    width: 10vw;
  }
  .text-input {
    width: 10vw;
  }
}
</style>

index.js

import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home
  },
  {
    path: "/about",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue")
  }
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes
});

export default router;

Upvotes: 0

Phil
Phil

Reputation: 165069

Looks like a race-condition brought on by a possible circular dependency (main -> App -> Home -> main).

I would suggest moving your bus to its own module instead of main. See here for an example

// src/event-bus.js
import Vue from 'vue'
export default new Vue()

and then in Home.vue and About.vue

import bus from '@/event-bus'

Also, your About component is listening for the wrong event. Home emits "msg" but About listens for "message". They should use the same event name.

Demo ~ https://codesandbox.io/s/serverless-frog-kvtoj?file=/src/event-bus.js

Upvotes: 1

Related Questions