1

I'm trying to create a dynamic component and pass a prop to it. I'm getting the warning: Component is missing template or render function. The component is being rendered, but i'm still getting the warning and the prop is not being passed to it.

Parent:

<template lang="pug">
q-page
  component(:is="detailsComponent" v-bind="selectedRule")
</template>

<script lang="ts">
import { defineComponent, ref, shallowRef, onMounted } from 'vue'
import { useStore } from 'vuex'
import { storeKey } from '../store'
import { useRoute, useRouter } from 'vue-router'
import { RuleList } from '../components/models'

export default defineComponent({
  name: 'CodeDetails',
  setup() {
    const store = useStore(storeKey)
    const route = useRoute()
    const router = useRouter()

    const detailsComponent = shallowRef({})
    const selectedRule = ref({} as RuleList)

    const selectComponent = async (ruleName: string) => {
      let fileName = ''
      switch (ruleName) {
        case 'retailFoodRules': fileName = 'FoodDetails'
        break
        case 'generalRules': fileName = 'GeneralDetails'
        break
        case 'poolRules': fileName = 'PoolDetails'
        break
        default: fileName = 'OtherDetails'
      }
      const component = await import(`../components/${fileName}`) as unknown
      detailsComponent.value = component.default as RuleList
    }

    onMounted(() => {
      const selected = JSON.parse(route.params.ruleString as string) as RuleList
      const ruleName = route.params.rule
      if (route.params) {
        selectedRule.value = selected as unknown as RuleList
        void store.dispatch('searchResults/saveSelectedRule', selected)
        // void store.dispatch('searchResults/saveRuleName', ruleName)
        void selectComponent(ruleName as string)
      } else if (!route.params && store.state.searchResults.selectedRule) {
        selectedRule.value = store.state.searchResults.selectedRule
        // selectComponent(store.state.searchResults.ruleName)
      } else {
        router.go(-1)
      }
    })

    return { detailsComponent, selectedRule }
  },
})
</script>

Child (the other dynamic child components are similar):

<template lang="pug">
q-card(flat)
  q-card-section
    q-item-label.text-caption.text-grey-9 Description
    q-item-label.text-subtitle1(v-html="selectedRule.Description")
  q-separator
  q-card-section
    q-item-label.text-caption.text-grey-9 Classification
    q-item-label.text-subtitle1(v-html="selectedRule.Classification" :class="{'text-negative': selectedRule.Classification === 'Priority', 'text-orange-9': selectedRule.Classification === 'Priority Foundation'}")
  q-separator
  q-card-section
    q-item-label.text-caption.text-grey-9 Section
    q-item-label.text-subtitle1(v-html="selectedRule.Section")
  q-separator
  q-card-section
    q-item-label.text-caption.text-grey-9 Category
    q-item-label.text-subtitle1(v-html="selectedRule.Category")
  q-separator
  q-card-section
    q-item-label.text-caption.text-grey-9 Compliance Categories
    q-item-label.text-subtitle1(v-html="selectedRule.Compliance")
  q-separator
  q-card-section
    q-item-label.text-caption.text-grey-9 Rule Text
    q-item-label.text-subtitle1(v-html="selectedRule.FullText")
</template>

<script lang="ts">
import { defineComponent, toRefs } from 'vue'
import { RuleList } from '../components/models'

export default defineComponent({
  name: 'FoodDetails',
  setup(props) {
    // console.log(Object.assign({}, props))
    const selectedRule = toRefs(props.selectedRule as RuleList)

    return { selectedRule }
  }
})
</script>

In the child component I get the error: Property 'selectedRule' does not exist on type '{}'. on the line const selectedRule = toRefs(props.selectedRule as RuleList) so it's not seeing the prop that was passed. The odd thing is that if I examine the child component with the Vue devtools it shows selectedRule as an attr but not as a prop. Am I doing something wrong or is this a Quasar quirk?

2 Answers 2

1

For the parent component it looks fine, but for the child one you add the props option :

<script lang="ts">
import { defineComponent, toRefs } from 'vue'
import { RuleList } from '../components/models'

export default defineComponent({
  name: 'FoodDetails',
 props:{
     selectedRule : {
        type : Object as PropType<RuleList >
     }
 },
  setup(props) {
    // console.log(Object.assign({}, props))
    const selectedRule = toRefs(props.selectedRule)

    return { selectedRule }
  }
})
</script>

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

Comments

0

I changed this line in the parent component from:

component(:is="detailsComponent" v-bind="selectedRule")

back to:

component(:is="detailsComponent" :selectedRule="selectedRule")

In the child key I added a prop key, used Object.assign() to get the prop value, since it comes in as a proxy, and removed toRef(), since it's not reactive anyway.

export default defineComponent({
  name: 'FoodDetails',
  props: {
    selectedRule: {
      type: Object,
      required: true
    }
  },
  setup(props) {
    const ruleObject = Object.assign({}, props.selectedRule) as RuleList

    return { ruleObject }
  }
})
</script>

The Component is missing template or render function. warning is still there, even though the component is rendering and displaying the data from the prop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.