DEV Community

Discussion on: Dynamic components using VueJS

Collapse
 
lainpavot profile image
Lain • Edited

Hello!
Thanks for your article.
I still have one question:
When you do

<component v-bind:is="something"></component>

If "something" contains a bad value (non-existing component), it doesn't throws any error.
How can we handle this case?

To give you a better background:

We have an SPA, and the user can modify the location hash to access articles:

http://mysite.com/index.html#super-article

This will load the async component "super-article", and show it via the "component" tag. I'd like to handle the case when a user enters a bad value (this is not usual, but anyway... Want to handle this bad case).

Do you know how to do that? (I don't like the "white list" solution...)

Collapse
 
pikax profile image
Carlos Rodrigues

Hi Lain,

You welcome :)

It will depend if the something is an lazy loaded component or component definition object.

In your case I will reckon you fetch the article from the database and then render, in that case if the response of the api is empty or 404 you can render a fallback component.

Collapse
 
lainpavot profile image
Lain • Edited

Thank you for your quick response!

I was hoping for something like <div v-except-nonexists> or something like that.

In my case, I have no way to trigger any 404 error, because each article's component is registered using it's metadata (name, tags, ...), and then it's loaded lazily only when my <component> tag asks for it. But Vue does nothing at all if the given component does not exists.

I'll keep my whitelist solution because the solution you provides implies to rewrite the whole loading system: I register a (lazy) component from each article, keep track of all registered articles, and if the article referenced by the location hash has never been registered, I show an error with v-if/v-else:

  <component v-if="loaded_articles[curent_page]" :is="curent_page"></component>
  <div v-else class="article article-content">
    <previous-button></previous-button>
    <h3>{{curent_page}}</h3>
    <p>{{$t("articles.article_not_found")}}</p>
  </div>

This method prevents any additional request to the server...

Thread Thread
 
pikax profile image
Carlos Rodrigues

It if you loading through webpack, it's simple, because import will throw an exception.

What do you mean by:

Vue does nothing at all if the given component does not exists.

You should be able to add that condition to v-if, no?

Are you registering the components using Vue.component()?

Thread Thread
 
lainpavot profile image
Lain

No, I don't use webpack.

Yes, I use Vue.component(name, promise) to register my components.

When my Vue instance is mounted, I set the language, and it triggers the loading of corresponding articles' components. Here is a simplified version of my code:

    function load_article(article, header, err_code) {
        // here, "article" is the raw html of my article
        // We'll insert it into the article's template
        return {
            data: {// some data...
            },
            template: `a template ${article} that encapsulate each article`
        }
    }
    function loader (header) {
        return (resolve, reject) => {
            vm.make_promise({
                url: `/article/${lang}/${header.name}.html`
            })
            .then((data) => {
                resolve(load_article(data, header, 200))
            })
            .catch((data) => {
                resolve(load_article(data, header))
            });
        }
    }
    var lang = vm.lang;
    headers = articles_headers();
    var loaded_articles = {};
    for(var i in headers) {
        header = headers[i];
        Vue.component(`${lang}-${header.name}`, loader(header));
        loaded_articles[`${lang}-${header.name}`] = true;
    }
    return loaded_articles;

And then, I have the code I wrote in my previous comment, with "curent_page" being the name of the article.

But, if we provide an article name that does not exists (and so, a component that is not registered), Vue shows a warning in the console, and that's all: [Vue warn]: Unknown custom element ....

Perhaps there's a way to tell Vue to call a given function when this happens?

Thread Thread
 
pikax profile image
Carlos Rodrigues

you should be able to check if the component is register by accessing Vue.options.components