简体   繁体   中英

VueJS: Child component not getting prop data from parent

NOTE: This is not a duplicate question as none of the answers here have been able to solve my problem.

Child component:

<template>
  <div>
    <v-card>
      <v-card-text>
        <p> Activity for Financial Year {{ this.currentFinancialYear.string_date }}
        </p>
      </v-card-text>
      <div class="px-3 pt-5">
        <v-select
          label="Financial Year"
          v-model="currentFinancialYear"
          :items="years"
          item-text="string_date"
          :return-object="true"
        ></v-select>
      </div>
    </v-card>
  </div>
</template>

<script>

export default {
  name: 'HeatMap',
  props: {
    years: {
      type: Array
    },
    financialYear: {
      type: Object
    },
    cardWidth: {
      type: String,
      default: '860px'
    }
  },
  data() {
    return {
     currentFinancialYear: {}
    }
  },
  watch: {
    currentFinancialYear (newVal, oldVal) {
      if (newVal) {
        this.getData()
        return newVal
      }
      return oldVal 
    },
    financialYear (newVal, oldVal){
      this.currentFinancialYear = newVal
    },
    years (newVal) {
      return newVal
    }
  },
  methods: {
    getData() {
      // Some axios code
    }
  }
</script>

parent component:

<template>
  <div>
    <v-layout class="headline pt-5" align-center> <p>Pulse</p> </v-layout>
    <HeatMap
        :years='years'
        :financialYear='finacialYear'
        :cardWidth="'860px'"
    />
  </div>
</template>

<script>
import HeatMap from '@/components/charts/HeatMap'
import { getYears } from '@/services/MetricsService'

export default {
  name: 'MetricsDisplay',
  components: {
    HeatMap
  },
  data () {
    return {
        years: [],
        finacialYear: {}
    }
  },
  created () {
    getYears().then(response => {
      for (var i = 0 ; i < response.data.data.items.length - 1 ; i++) {
        this.years[i] = {
          start: new Date(response.data.data.items[i], 3, 1).toISOString(),
          end: new Date(response.data.data.items[i] + 1, 2, 31).toISOString(),
          string_date: response.data.data.items[i] + ' - ' + (response.data.data.items[i] + 1)
        }
      }
      this.financialYear = this.years[this.years.length - 1]
    })
  }
}
</script>

So, as you can see, the parent sends the array years and the object financialYear as props to the child. I have placed a watch on the those props in the child component so as to update the data as and when it comes. But for some reason, currentFinancialYear comes as undefined .

Also, as you can see in the child , the v-select uses the years array to fill its content. The first time the component is loaded, there are no elements in the v-select which indicates that the years are empty too. Since the currentFinancialYear is responsible for the selection of the item of the v-select , no item is selected as well.

Just to show what the data looks like:

  1. years :
[
   {
      end: "2018-03-31T18:30:00.000Z"
      start: "2017-03-31T18:30:00.000Z"
      string_date: "2017 - 2018"
   },
   {
      end: "2019-03-31T18:30:00.000Z"
      start: "2020-03-31T18:30:00.000Z"
      string_date: "2017 - 2018"
   }
]
  1. currentFinancialYear :
[
   {
      end: "2018-03-31T18:30:00.000Z"
      start: "2017-03-31T18:30:00.000Z"
      string_date: "2017 - 2018"
   }
]

I am aware of the fact that the parent-child lifecycle looks like this:

  1. created() of parent
  2. created() of child
  3. mounted() of child
  4. mounted() of parent.

I have read the Vue.js guidelines where they tell us to put the prop variables under watch which is why I have done it this way.

If I write a console.log(this.years) in the created() , the years are getting printed. Even so, I cannot initialize currentFInancialYear of get the years in my v-select .

I have also tried to initialise currentFinancialYear in mounted() and created() but with no luck.

The solution that I require is:

On the first load of the component, the data values of the child , years , financialYear , currentFinancialYear should have the values that have been passed from the parent, such that my v-select has elements.

Can someone please explain how to exactly time parent-child prop data passing?

I think the issue you are having is a rather semantic one to do with what an array or object actually is and how you watch it.

Obviously we can define an object (or array) as const something = {} and can do this because the constant is truly constant and is an object container, that doesn't change, however the contents of the container can change.

That is what the problem is here because you are setting up to watch the object or array container and not its contents. Fortunately vue has us covered on this with some of it's more obscure functionality. You will need to utilise 'immediate' and 'handler' in your watch, like so:

watch: {
  currentFinancialYear: {
      handler: function (val, oldVal) {
        if (newVal) {
          this.getData()
          return newVal
        }
        return oldVal 
      },
      immediate: true
    },
}

You can see all about it in the docs or there is a blog post covering it here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM