简体   繁体   中英

How to ensure that parent is passing populated props to a child component in VueJS

Good day all. Imagine we have a parent and a child component ie PracticePersonLists (parent) -> BCardHeaderWithButton (child). Now the child consists of a vue-multiselect like so where leftAction is an Object prop

<!-- Multiselect -->
<multiselect
  v-if="leftAction.type === 'options'"
  v-model="leftAction.model"
  :options="leftAction.options"
  :placeholder="leftAction.placeholder"
  :searchable="true"
  :show-labels="true"
  :allow-empty="false"
/>

The parent renders the child like so:

<b-card-header-with-button
  v-if="(isHR && (person.md_current === 1))"
  card-title="Events"
  :left-action="eventsLeftAction"
  :right-action="eventsRightAction"
  @rightActionClick="addEvent()"
/>

eventsLeftAction is a data property inside the parent looking like so:

eventsLeftAction: {
  show: true,
  type: 'options',
  options: this.eventsFilters,
  model: this.compEventsLeftActionModel,
  placeholder: 'Select Event'
}

eventsFilters is generated in the created hook of the parent

this.eventsFilters = await buildNonBackEndFilterOptions(this.events, 'eventHead', 'eventGroup')

but the problem is that on page load , the child component cannot find its leftAction.options so it comes back as undefined. We think it is something connected with the fact that child components get rendered before parent, hence it is looking for data that doesn't exist yet.... usually we overcome this by setting a dataLoaded Boolean and render the child only if the Boolean is true but it doesn't seem to work in this case

Would anybody know how to overcome this issue ? Thanks

The only solution we could come up for now is to store the options in Vuex from the created hook of the parent and then pull them with mapState in the child.

Parent:

this.eventsFilters = await buildNonBackEndFilterOptions(this.events, 'eventHead', 'eventGroup')
this.setPracticePersonListsEventsFilters(this.eventsFilters)

methods: {
    ...mapMutations('practice', ['setPracticePersonListsEventsFilters']),
}

Child:

<multiselect
  v-if="leftAction.type === 'options'"
  v-model="leftAction.model"
  :options="compOptions"
  :placeholder="leftAction.placeholder"
  :searchable="true"
  :show-labels="true"
  :allow-empty="false"
/>

computed: {
  ...mapState('practice', ['practicePersonListsEventsOptions']),
  compOptions () {
    switch (this.$route.name) {
      case 'app.practice.person.lists':
        return this.practicePersonListsEventsOptions
      default:
        return ''
    }
  }
}

If anybody knows a better solution, we would appreciate if you share.

this is not true. parent created called before child rendered. the problem in you code is

eventsLeftAction: {
  show: true,
  type: 'options',
  options: this.eventsFilters,
  model: this.compEventsLeftActionModel,
  placeholder: 'Select Event'
}

you cannot set option:this.eventsFilters the use of this is not valid here at all.

you should do it like this

eventsLeftAction: {
  show: true,
  type: 'options',
  options: null,
  model: null,
  placeholder: 'Select Event'
}

and in the created hook set the values

async created(){
    //you can here whatever you want. its called before child rendered
    this.eventsLeftAction.options= await buildNonBackEndFilterOptions(this.events, 
        'eventHead', 'eventGroup')
}

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