ARTLoe
ARTLoe

Reputation: 1799

Trigger child component method from parent event

I am very new to VueJS and JavaScript and your help would be much appreciated.

My method "greet" is not working and I am unsure why. When I click on the button "change to bar" I get the error:

[Vue warn]: Property or method "greet" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

found in

---> <Chatjsvue> at src\components\vueChartjs\Chatjsvue.vue
       <App> at src\App.vue
         <Root>

chartjs.vue

<template src="../../views/chartjshtml/chartsjs.html"></template>
<script>
  import LineChart from '@/assets/javascripts/chartjsline'

    export default {
    components: {
      'line-chart': LineChart 
    }
  }
</script>

chartsjs.html

<div class="wrapper">
    <div>
     <ul>
       <li><button v-on:click="greet()">change to bar</button></li>
       <li><line-chart></line-chart></li>
     </ul>
    </div>
</div>

chartsjsline.js

import { Line } from 'vue-chartjs'

export default {
  extends: Line,
  data() {
      return {
         datacollection: {
            //Data to be represented on x-axis
            labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
            datasets: [{
               label: 'Activities ChartJS Line',
               backgroundColor: '#f87979',
               pointBackgroundColor: 'white',
               borderWidth: 1,
               pointBorderColor: '#249EBF',
               //Data to be represented on y-axis
               data: [40, 20, 30, 50, 90, 10, 20, 40, 50, 70, 90, 100]
            }]
         },
         //Chart.js options that controls the appearance of the chart
         options: {
            scales: {
               yAxes: [{
                  ticks: {
                     beginAtZero: true
                  },
                  gridLines: {
                     display: true
                  }
               }],
               xAxes: [{
                  gridLines: {
                     display: false
                  }
               }]
            },
            legend: {
               display: true
            },
            responsive: true,
            maintainAspectRatio: false
         },
      }
   },
   methods: {
      greet() {
        alert('hello');
      }
    },
    mounted() {
      //renderChart function renders the chart with the datacollection and options object.
      this.renderChart(this.datacollection, this.options)
   }
}

Upvotes: 6

Views: 13487

Answers (2)

ghybs
ghybs

Reputation: 53185

Your <line-chart> component (instance of LineChart) is a child component of your Chatjsvue component.

The child methods remain bound to those instances.

However it is extremely easy from the parent component to access its child component, and from there to execute their methods:

  1. Keep a reference to your child component, using the ref special attribute: <line-chart ref="myLineChart"></line-chart>
  2. Within a parent method, access the referred child using this.$refs.myLineChart.
  3. Then you have access to everything on this child instance, including its methods: this.$refs.myLineChart.greet()

Working example:

Vue.component('chart-js', {
  template: '#chartjs',
  methods: {
    lineChildGreet() {
      // Access the child component through $refs.
      // Then you can execute its methods.
      this.$refs.myLineChart.greet();
    },
  },
});

Vue.component('line-chart', {
  template: '#lineChart',
  methods: {
    greet() {
      alert('hello');
    },
  },
});

var app = new Vue({
  el: '#app',
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
  <chart-js></chart-js>
</div>

<template id="chartjs">
  <div class="wrapper">
    <div>
     <ul>
       <li><button v-on:click="lineChildGreet">greet on child component</button></li>
       <!-- Keep a REFerence to the child component -->
       <li><line-chart ref="myLineChart"></line-chart></li>
     </ul>
    </div>
  </div>
</template>

<template id="lineChart">
  <span>LineChart</span>
</template>

Upvotes: 16

Luke Ramsden
Luke Ramsden

Reputation: 734

You need to add the greet() method to the chartjs.vue component, instead of chartsjsline.

Upvotes: 1

Related Questions