2

How do I pass data from one component to another when using Vue router?

I'm building a simple CRUD app that have different components. My conponents are:

  • App.vue - where I render the router-view
  • Contacts.vue - where I have the array of objects of contacts
  • ContactItem.vue - handle how the contact is displayed (gets contact as a prop from contact.vue
  • AddContact.vue - add new contact
  • EditContact.vue - edit selected contact

On the AddContact component, I have a form the user fills and then clicks on the submit button to add the form to the main component in Contacts.vue but when I emit an event and call it on the Contacts.vue component, it doesn't work. I get no output but from devtools I can see the event was triggered from AddContact.vue component.

Here is the Github link

<!-- App.vue -->
<template>
  <div>
    <Navbar />
    <div class="container">
      <router-view @add-contact="addContact" />
    </div>
  </div>
</template>

<script>
import Navbar from "./components/layout/Navbar";
export default {
  components: {
    Navbar
  }
};
</script>
<!-- Contacts.vue -->
<template>
  <div>
    <div v-for="(contact) in contacts" :key="contact.id">
      <ContactItem :contact="contact" />
    </div>
  </div>
</template>

<script>
import ContactItem from "./ContactItem";

export default {
  components: {
    ContactItem
  },
  data() {
    return {
      contacts: [
        {
          id: 1,
          name: "John Doe",
          email: "[email protected]",
          phone: "55-55-55"
        },
        {
          id: 2,
          name: "Karen Smith",
          email: "[email protected]",
          phone: "222-222-222"
        },
        {
          id: 3,
          name: "Henry Johnson",
          email: "[email protected]",
          phone: "099-099-099"
        }
      ]
    };
  },
  methods: {
    addContact(newContact) {
      console.log(newContact);
      this.contacts = [...this.contacts, newContacts];
    }
  }
};
</script> 
<!-- AddContact.vue -->
<template>
  <div>
    <div class="card mb-3">
      <div class="card-header">Add Contact</div>
      <div class="card-body">
        <form @submit.prevent="addContact">
          <TextInputGroup
            label="Name"
            name="name"
            placeholder="Enter your name..."
            v-model="name"
            for="name"
          />
          <TextInputGroup
            type="email"
            label="Email"
            name="email"
            placeholder="Enter your email..."
            v-model="email"
          />
          <TextInputGroup
            type="phone"
            label="Phone"
            name="phone"
            placeholder="Enter your phone number..."
            v-model="phone"
          />

          <input type="submit" value="Add Contact" class="btn btn-block btn-light" />
        </form>
      </div>
    </div>
  </div>
</template>

<script>
import TextInputGroup from "../layout/TextInputGroup";
export default {
  components: {
    TextInputGroup
  },
  data() {
    return {
      name: "",
      email: "",
      phone: ""
    };
  },
  methods: {
    addContact() {
      const newContact = {
        name: this.name,
        email: this.email,
        phone: this.phone
      };
      this.$emit("add-contact", newContact);
    }
  }
};
</script>
7
  • Can you please show your Contacts.vue, at least the part where you have the <AddContact> component and any event handling methods for it Commented Oct 15, 2019 at 22:39
  • @Phil I just updated the question with more code to show Commented Oct 15, 2019 at 22:52
  • So where is <AddContact>? How is it included in your app? Commented Oct 15, 2019 at 22:57
  • Yeah, from <router-view> Commented Oct 15, 2019 at 23:13
  • 1
    I don't really agree and neither does Vue ~ vuejs.org/v2/style-guide/… Commented Oct 15, 2019 at 23:40

1 Answer 1

2

Well there are more ways to send data from component to component:

You could create a new Vue instance in your main.js file and call it eventBus

  export const eventBus = new Vue();

After that you can import this bus wherever you need it:

  import { eventBus } from "main.js"

Then you can send events over this global bus:

  eventBus.$emit("add-contact", newContact);

At the other component you need to import this bus again and listen to this event in your "created" lifecycle:

  created(){
     eventBus.$on("add-contact", function (value){
                                   console.log(value)
                               })
   }

The other way is to store it centralized in vuex state. With "created" you can call this data. Created gets executed after your vue instance is created

Sign up to request clarification or add additional context in comments.

8 Comments

It's not working. It only shows that it's fired from the root but I don't see any console logs of the value from the input fields from AddContact I updated my Github repo to reflect the new changes
Well i see why it doesnt work because when you add some contacts you dont switch to your contacts back you still stay on the add page. well i have fixed this problem with the help of vuex. i will send you an github link to download it.
thanks for your help. I know Vuex is good and also know how to use it. I was looking for a way to do this without the additional complexity of Vuex and adding more overhead to my code. Although, if I can confirm that the only way this would work is if I use Vuex then I'll like you to update your answer so I'll make it the answer.
no problem, this answer above only works if you routing instantly back to your contact overview. but nevermind, vuex is the better choice here. still got small problem to make this work because i code with nuxt.js and there is vuex slighly different
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.