Reputation: 2137
I'd like to conditionally import a component in the vue router. Here is what I have for the moment:
children: [
{
path: ':option',
component: () => import('../components/Option1.vue'),
},
],
Depending on what :option
is, I want to import a different component (Option1.vue
, Option2.vue
, etc.). I know I could put several children
but i actually need the option
variable in my parent component (I make tests if the route has an option).
How would it be possible to do that?
Thanks in advance :)
Upvotes: 1
Views: 9448
Reputation: 1
Oh this is really cool so I can foreach component in componentlist, and then render the components in a custom order for each page 🤩
In theory, you can have a blocks array and load all content in a custom order
let blocks = [
{'type': 'header', 'blockContent': [headerData]},
{'type': 'section1', 'blockContent': [headerData]},
{'type': 'component1', 'blockContent': [componentData]},
{'type': 'component2', 'blockContent': [componentData]},
{'type': 'section2', 'blockContent': [headerData]},
{'type': 'component3', 'blockContent': [componentData]},
{'type': 'footer', 'blockContent': [footerData]}
]
<div v-for(block in blocks)>
<div v-if="block.type == 'header'">
</header-component>
</div>
<div v-if="block.type == 'section1'">
</section1-component>
</div>
<div v-if="block.type == 'section2'">
</section2-component>
</div>
<div v-if="block.type == 'component1'">
</component1-component>
</div>
<div v-if="block.type == 'component2'">
</component2-component>
</div>
<div v-if="block.type == 'component3'">
</component3-component>
</div>
<div v-if="block.type == 'footer'">
</footer-component>
</div>
</div>
This was already answered so I felt free to rant incase someone needs this idea in the future :)
Upvotes: 0
Reputation: 2137
Here is something that works in VueJS3:
<template>
<component :is="userComponent"/>
</template>
<script>
import { defineAsyncComponent } from 'vue';
import { useRoute, useRouter } from 'vue-router';
export default {
computed: {
userComponent() {
const route = useRoute();
const router = useRouter();
const components = {
first: 'Option1',
second: 'Option2',
third: 'OtherOption',
fourth: 'DefaultOption',
};
if (components[route.params.option]) {
return defineAsyncComponent(() => import(`./options/${components[route.params.option]}.vue`));
}
router.push({ path: `/rubrique/${route.params.parent}`, replace: true });
return false;
},
},
};
</script>
Source: https://v3-migration.vuejs.org/breaking-changes/async-components.html
And it's possible to get an error message like this one for the line with "return
":
Syntax Error: TypeError: Cannot read property 'range' of null
In that case, it means you probably want to migrate from babel-eslint
to @babel/eslint-parser
(source: https://babeljs.io/blog/2020/07/13/the-state-of-babel-eslint#the-present)
Upvotes: 1
Reputation: 63139
You can create a loader component containing a dynamic component instead of doing conditional routing. In the loader, you'll conditionally lazy load the option component based on the route param. Not only is this easier when routing, you also don't have to manually import anything, and only options that are used will be imported.
Step 1. Route to the option loader component
router
{
path: ':option',
component: () => import('../components/OptionLoader.vue'),
}
Step 2. In that option loader template, use a dynamic component which will be determined by a computed called optionComponent
:
OptionLoader.vue
<template>
<component :is="optionComponent" />
</template>
Step 3. Create a computed that lazy loads the current option
OptionLoader.vue
export default {
computed: {
optionComponent() {
return () => import(`@/components/Option${this.$route.params.option}.vue`);
}
}
}
This will load the component called "Option5.vue", for example, when the option
route param is 5
. Now you have a lazy loaded option loader and didn't have to manually import each option.
Edit: OP has now indicated that he's using Vue 3.
For Vue 3, change the computed to use defineAsyncComponent
:
OptionsLoader.vue
import { defineAsyncComponent } from "vue";
computed: {
optionComponent() {
return defineAsyncComponent(() =>
import(`@/components/Option${this.$route.params.option}.vue`)
);
}
}
Upvotes: 6