SmellydogCoding
SmellydogCoding

Reputation: 464

Vue.js 3, Quasar 2 - Component is missing template or render function

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?

Upvotes: 1

Views: 1797

Answers (2)

SmellydogCoding
SmellydogCoding

Reputation: 464

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.

Upvotes: 0

Boussadjra Brahim
Boussadjra Brahim

Reputation: 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>

Upvotes: 1

Related Questions