0
votes

I have two components: child Dog and parent App. Inside the App I'm trying to change Dog's properties hasName and name on button click. However I get an error: hasName is undefined.

Child component:

Dog.vue

<template>
  <div>
    <div>A Dog</div>
    <div v-if="hasName">Name: {{ name }}</div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      hasName: false,
      name: "",
    };
  },
};
</script>

Parent component:

App.vue

<template>
<div id = "app">
  <img alt="Vue logo" src="./assets/logo.png" />
  <Dog />
  <button @click="handleClick">Click</button>
</div>
</template>

<script>
import Dog from "./components/Dog.vue";
export default {
  name: "App",
  components: {
    Dog,
  },
  methods: {
    handleClick: function () {
      this.Dog.hasName = true;
      this.Dog.name = "Jerry";
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

I get the error:

Cannot set property 'hasName' of undefined

Vue fiddle: https://codesandbox.io/s/upbeat-resonance-b65pd?file=/src/App.vue

2

2 Answers

1
votes

You can't access the data of a child component like this.

In your App.vue component, when you access Dog, it's simply a reference to the component itself, not a reference to any mounted version of the component.

Imagine how if you had multiple dog components. How would you be able to tell the component data apart?

You need to use props to pass data from a parent to a child.

For example:

App.vue

<template>
<div id = "app">
  <img alt="Vue logo" src="./assets/logo.png" />
  <Dog :name="dog.name" :has-name="dog.hasName" />
  <button @click="handleClick">Click</button>
</div>
</template>

import Dog from "./components/Dog.vue";
export default {
  name: "App",
  data() {
      return {
          dog: {
              hasName: false,
              name: '',
          },
      }
  },
  components: {
    Dog,
  },
  methods: {
    handleClick: function () {
      this.dog.hasName = true;
      this.dog.name = "Jerry";
    },
  },
};

Dog.vue

<template>
  <div>
    <div>A Dog</div>
    <div v-if="hasName">Name: {{ name }}</div>
  </div>
</template>

<script>
export default {
  props: {
      hasName: {
          required: true,
          type: Boolean,
      },
      name: {
          required: true,
          type: String,
      },
  },
};
</script>

When you modify the parent object dog, the data is automatically passed to the child via props and updated there too.

Please read the VueJS docs here to learn more about props

0
votes

You need to emit your event listening actions.hasName is not a data object hence it wont be defined