fairycode
fairycode

Reputation: 53

Unknow custom element error during passing component as a prop in VueJS

Could you explain why Vue tells me, that Unknown custom element: <MyComponent> - did you register the component correctly? here:

const CustomComponent = Vue.component('CustomComponent', {
  template: '<div>test</div>'
})

const RenderComponent = Vue.component('RenderComponent', {
  props: {
    component: {
        type: [Function, String]
    }  
  },
  template: '<component :is="component"></component>'
})

new Vue({
  el: '#app',
  components: {
    MyComponent: CustomComponent,
    RenderComponent
  },
  template: '<render-component component="MyComponent"></render-component>'
})

https://jsfiddle.net/2qobuj4y/1/

How to pass components to a prop properly here? Are there some examples?

Upvotes: 2

Views: 174

Answers (1)

Dan
Dan

Reputation: 63059

MyComponent doesn't exist so you don't want to list it in your app's components. Change your app code to:

new Vue({
  el: '#app',
  components: {
    CustomComponent, // Not actually being used, the template passes a string
    RenderComponent
  },
  template: '<render-component component="CustomComponent"></render-component>'
})

Here is a fiddle

Explanation

You have properly registered CustomComponent as MyComponent in the main app component, and you could use it directly in its template. But then you are also passing a string with the value "MyComponent" to the RenderComponent component. RenderComponent then tries to instantiate a MyComponent component, but none exists in the global scope where it is looking for it. (It only exists with that name within the main app component where you registered it.)

Alternatively, if you were to use a binding instead when you pass MyComponent (i.e. :component instead of component) it still would not work because you can't pass components as props.

(EDIT: You can but not the traditional way. This works: :foo="$options.components.foo". See this comment from Evan You)

Interesting Alternative

You mentioned trying to pass it from data instead, and while I can't say if it's a good practice, it does work. It could get uglier if you ever migrated to single-file components where you wouldn't have access to a global scope, and it's a little confusing, but it does work:

new Vue({
  el: '#app',
  data: {
    MyComponent: CustomComponent // Taken from global scope
  },
  components: {
    // CustomComponent, // No need in this version
    RenderComponent
  },
  template: '<render-component :component="MyComponent"></render-component>'
})

Here is that fiddle

Upvotes: 1

Related Questions