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?
Related
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,
}));
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 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 a vue-router like this
import Vue from 'vue';
import Router from 'vue-router';
import http from './helpers/http';
import Home from './views/Home/Home.vue';
import HomeMentor from './views/Home/HomeMentor.vue';
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: '',
component: () => import(/* webpackChunkName: "Container" */ './components/Container.vue'),
children: [
{
path: '/',
name: 'Dashboard',
component: {
render(c) {
http.request('GET', '/profile').then( async ({ data }) => {
console.log(data.profile.email)
if (data.profile.email === "vickysultan08#gmail.com") {
console.log('sip')
return c(HomeMentor);
} else {
return c(Home);
}
});
}
},
}
],
beforeEnter: isAuthentication,
}
});
The thing is, only the return component inside the conditional statement that cannot executed inside axios statement as the result below
While the return component inside the conditonal statement can be executed outside the axios statement like this
children: [
{
path: '/',
name: 'Dashboard',
component: {
render(c) {
a = 10
if (a === 10) {
console.log('sip')
return c(HomeMentor);
} else {
return c(Home);
}
}
},
}
],
I'm quite new in Vue JS and have to continue other person's code. Any advice?
Unfortunately, render functions must be synchronous.
What you may be able to do instead is simply use an async function to return the component, ala Async Components and Lazy Loading Routes.
const Dashboard = () => http.request('GET', '/profile').then(({ data }) => {
console.log('profile email', data.profile.email)
let isMentor = data.profile.email === 'vickysultan08#gmail.com'
let componentPath = `./views/Home/${isMentor ? 'HomeMentor' : 'Home'}.vue`
return import(componentPath) // chains in the "import" promise
})
and then in your route...
component: Dashboard,
If lazy-loading the component isn't working for you, you could always try pre-loading it
import http from './helpers/http';
import Home from './views/Home/Home.vue';
import HomeMentor from './views/Home/HomeMentor.vue';
const Dashboard = () => http.request('GET', '/profile').then(({ data }) => {
let isMentor = data.profile.email === 'vickysultan08#gmail.com'
return isMentor ? HomeMentor : Home
})
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'];
},