How to display stub component when component is not found in vue

Viewed 149

I am trying to catch situation, when component is not found, ie:

{
   template: '<some-unknown-component></some-unknown-component>'
}

At that moment, Vue warns us with unknown custom element: <some-unknown-component>...

I would like to step in when some-unknown-component is not found and then use another component instead, like stub-component:

{
   name: 'stub-component',
   props: ['componentName'],
   template: '<p>component ${componentName} does not exists, click here to create...</p>'
}

UPDATE: I am looking for solution without changing the template itself, so no v-if and component added.

2 Answers

Vue exposes a global error and warning handler. I managed to get a working solution by using the global warnHandler. I don't know if it is exactly what you are looking for, but it may be a good starting point. See the working snippet (I think it is quite self explanatory).

Vue.config.warnHandler = function (err, vm, info)  {
  if (err.includes("Unknown custom element:")) {
    let componentName = err.match(/<.*>/g)[0].slice(1, -1)
    
    vm.$options.components[componentName] = Vue.component('stub-component', {
       props: ['componentName'],
       template: `<p>component "${componentName}" does not exists, click here to create...</p>`,
    });
    
    vm.$forceUpdate()
  } else {
    console.warn(err)
  }
};

new Vue({
  el: '#app',
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <unknown-component></unknown-component>
</div>

Vue stores the details of all the registered components in the $options.component property of the Vue instance.

So, you can check for the component availability using this.$options.component and if the component is present then load the component otherwise load the other component.

In the below example, suppose you have two different components and you want to load them on the availability, then you can create a computed property on the basis of it, load the component as needed.

var CustomComponent = Vue.extend({ template: '<h2>A custom Component</h2>' });

var AnotherComponent = Vue.extend({ template: '<h2>Custom component does not exist.</h2>' });

new Vue({
  el: "#app",
  components: {
    CustomComponent,
    AnotherComponent
  },
  computed: {
    componentAvailable () {
      return this.$options.components.CustomComponent
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <div v-if="componentAvailable">
    <custom-component />
  </div>
  <div v-else>
    <another-component />
  </div>
</div>

Related