I'd like to mock the route object to prevent test failures like TypeError: Cannot read properties of undefined when accessing route.x.
I tried:
const route = { fullPath: '/', path: '/' };
const options = {
mocks: {
route,
},
};
Since the route object is no longer a global object you have to do the following:
const route = { fullPath: '/', path: '/' };
vi.mock('vue-router', () => ({
useRoute: () => route,
}));
Related
I have the following path in my router
{
path: '/Page',
component: async () => {
const isUserLogged = await getUser()
const store = useStore()
if (userLogged && store.value1) {
return import('./pages/PublicPage/PublicPage.vue')
} else {
return import('./pages/NonPublicPage/NonPublicPage.vue')
}
},
},
}
Every time I enter this path, I need to return a different component depending on the value in the store, but the component is loaded only once.
I tried to rewrite the structure so that it uses beforeEnter as follows:
{
path: '/Page',
beforeEnter: async (to, from, next) => {
const isUserLogged = await getUser()
const store = useStore()
if (userLogged && store.value1) {
next({
component: () => import('./pages/PublicPage/PublicPage.vue'),
})
} else {
next({
component: () => import('./pages/NonPublicPage/NonPublicPage.vue'),
})
}
},
}
But this solution doesn't work. Without using a different path, I need to return a different component depending on the conditions. Is it possible to return a component in beforeEnter in next() or is there another solution to this problem?
i want to click the button to remove the property of 'keyword' in query,and request data again
const route = useRoute()
const router = useRouter()
//watch router query change,send request to get data
watch(
() => route.query,
() => {
//send request
searchStore.getSearchList(route.query)
},
{ immediate: true }
)
//remove keyword, update router , and refresh page
const removeKeyword = function () {
route.query.keyword = undefined
router.push({
name: 'search',
query: {...route.query}
})
}
it seems no problem, but router can't update and page can't refresh,so that means router.push() didn't work and router query didn't been watched.
but when i add a new property in query,it works!
router.push({
name: 'search',
query: {...route.query,a: 1}
})
so i have to choose this way to solve the problem
const removeKeyword = function () {
router.push({
name: 'search',
query: {...route.query, keyword: undefined}
})
}
i wonder know why it is and if it have a better solution.
Has anyone can help me?
I am trying to change the route of my components based on a value saved within the vuex store. There are four different template files, saved within different directories (template1, template2 etc). I am pulling the template id from the details store and depending on this value would like to render the component from the correct directory.
For example, if the template value in the store is 2 then load all the template2/profile component, if it is three load the template3/profile component.
import VueRouter from 'vue-router'
import store from '../store';
Vue.use(VueRouter)
const setComponent = componentName => {
return () => import(`../template${store.getters['detailsStore/getTemplate']}/views/${componentName}`)
}
const routes = [
{
path: '/',
redirect: '/details'
},
{
path: '/profile',
name: 'Profile',
//component: () => import('../template2/views/Profile') // - this is how i was importing the component but couldn't access vuex store
component: () => setComponent('Profile'),
},
{
path: '/details',
name: 'Details',
component: () => setComponent('Details'),
}
];
const router = new VueRouter({
mode: 'history',
routes
})
export default router
I thought creating the setComponent function would help,. but i just get a blank page. Any help would be much appreciated
Vue2:
Your component is not done loading. This will do it:
const asyncComp = async (componentName) => {
const component = await import(`../template${store.getters['detailsStore/getTemplate']}/views/${componentName}`)
return component;
};
{
path: '/profile',
name: 'Profile',
component: () => asyncComp('Profile'),
}
Vue 3 solution:
Here you will have defineAsyncComponent() available
https://vuejs.org/api/general.html#defineasynccomponent
const asyncComp = (compName) => defineAsyncComponent(() => import(`../template${store.getters['detailsStore/getTemplate']}/views/${compName}`);
I have router file, which contains all my routes.
Here is an example on one route:
path: '/events/:step',
children: [
{
path: '',
name: 'event.step',
components: {
default: Event,
sidebar: EventSidebar
}
}
],
props: {
default: ({ params, query: { id } }) => ({ id, ...params })
},
components: {
header: () => import('NavBar'),
default: () => import('Event')
},
async beforeEnter(to, from, next) {
if (step === 'login') { // can't find step
// do something
}
next()
}
I need to get the step param from route and if it is login do something in beforeEnter function.
How can I get it?
To get params from route you need to use to.params or from.params, if you want to access path you can get it from to.path or from.path depends what you need.
More info on https://router.vuejs.org/api/#routelocationnormalized
You can register global before guards using router.beforeEach:
router.beforeEach((to, from, next) => {
if (['Login', 'Signup'].includes(to.name) && logged_in)
next({ name: 'Home' })
else next()
})
https://router.vuejs.org/guide/advanced/navigation-guards.html
I have the following VueRouter route
{
path: '/playlists/:id',
name: 'videos',
component: Video,
props: {
videos: [],
},
beforeEnter(to, from, next) {
Vue.axios
.get('/playlistitems?playlistId='.concat(to.params.id))
.then((response) => {
to.params.videos = response.data
next((vm) => {
console.log(vm)
vm.videos = response.data
})
})
.catch((err) => console.log('error', err))
},
}
When the route is entered into everything executes as expected but I'm not sure how to pass the response.data to the route's component Videos
Question 1
Can you set the Vue component's props property from the Router?
Question 2
The route is a dynamic route. If the route and component is already loaded and the dynamic parameter changes....does beforeEnter still fire? If not where should I put my data fetching logic? Do I watch for route changes inside the Vue component?
1)
This might not be the most elegant approach, but here's a way to achieve that:
let videos = [];
export default new Router({ ... });
{
path: '/playlists/:id',
name: 'videos',
component: Video,
props: route => ({ videos }),
beforeEnter (to, from, next) {
Vue.axios.get('/playlistitems?playlistId='.concat(to.params.id))
.then((response) => {
// Now the data will be available when the props will be initialized
videos = response.data
next()
})
.catch((err) => console.log('error', err))
}
}
// Videos.vue
props: {
videos: Array
},
2)
IMHO, it would be easier if you could encapsulate the logic in the component.
What do I mean by that is that you could fetch your data in the created hook and set it to a variable that you defined in your data function.
data() {
return {
videos: []
}
},
created () {
Vue.axios.get('/playlistitems?playlistId='.concat(this.$route.params.id))
.then((response) => {
this.videos = response.data;
})
.catch((err) => console.log('error', err))
},
Another approach, which may be suitable or not, depending on what you're working on, would be to have a parent component that fetches multiple playlists which could be stored in vuex.
Thus, you would have another component that handles playlists/:id.
Within this last mentioned component, in your created hook, you would have something like this:
created () {
this.$store.commit('playlist/SET_CURRENT_PLAYLIST_ID', this.$route.params.id);
this.videos = this.$store.getters['playlits/getVideosByPlaylistId'];
},