vue router is undefined - vue.js

http://localhost:3000/apartamentai?filter[city]=Vilnius
import { ref, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
export default {
setup() {
const router = useRouter();
const route = useRoute();
console.log(router);
console.log(route);
onMounted(() => {
console.log(router);
console.log(route);
});
}
}
I get 4 undefined. What's wrong?
https://next.router.vuejs.org/guide/advanced/composition-api.html

You have to create and register the router in your app:
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
mode: 'history',
history: createWebHistory(),
routes: [],
});
createApp({})
.use(router)
.mount('#app');
as taken from here:
https://next.router.vuejs.org/guide/#router-view

Related

Vue router 3 not rendering nested routes

I'm trying to render my nested routes in Vue 3 using Vue Router 4.
routes/index.ts
import { createRouter, createWebHistory } from "vue-router";
import {NavbarLayout} from "#/layouts/NavbarLayout";
import AuthRoutes from "#/router/children/AuthRoutes";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
component: NavbarLayout,
// children: AuthRoutes,
},
],
});
export default router;
App.ts
import { defineComponent, h } from "vue";
import { VApp, VMain } from "vuetify/components";
export const App = defineComponent({
name: "App",
setup() {
return function render() {
// "Hello" is printed to the screen
return h(VApp, h(VMain, () => ["Hello", h("router-view")]));
};
},
});
NavbarLayout.ts
import { defineComponent, h } from "vue";
import { VContainer } from "vuetify/components";
import { useRoute } from "vue-router";
export const NavbarLayout = defineComponent({
name: "NavbarLayout",
setup() {
const route = useRoute();
// The alert pop up is not shown as well
alert("it should trigger this alert");
return function render() {
// "sub router" is not printed to the screen
return h(VContainer, () => ["sub router", h("router-view", { key: route.path })]);
};
},
});
The HTML being rendered
I have tried several combinations but so far nothing seems to work. Anyone has a clue on why the nested route is not being rendered?

Vue: Can't access Pinia Store in beforeEnter vue-router

I am using Vue 3 including the Composition API and additionally Pinia as State Management.
In the options API there is a method beforeRouteEnter, which is built into the component itself. Unfortunately this method does not exist in the composition API. Here the code, which would have been in the beforeRouteEnter method, is written directly into the setup method. However, this means that the component is loaded and displayed first, then the code is executed and, if the check fails, the component is redirected to an error page, for example.
My idea was to make my check directly in the route configuration in the beforeEnter method of a route. However, I don't have access to the Pinia Store, which doesn't seem to be initialized yet, although it is called before in the main.js.
Console Log
Uncaught Error: [🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?
const pinia = createPinia()
app.use(pinia)
This will fail in production.
Router.js
import { useProcessStore } from "#/store/process";
const routes: Array<RouteRecordRaw> = [
{
path: "/processes/:id",
name: "ProcessView",
component: loadView("ProcessView", "processes/"),
beforeEnter: () => {
const processStore = useProcessStore();
console.log(processStore);
},
children: [
{
path: "steer",
name: "ProcessSteer",
component: loadView("ProcessSteer", "processes/")
},
{
path: "approve/:code",
name: "ProcessApprove",
component: loadView("ProcessApprove", "processes/")
}
]
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
main.js
import { createApp } from "vue";
import "#/assets/bundle-bootstrap.css";
import App from "#/App.vue";
import { createPinia } from "pinia";
import router from "#/router";
import SvgIcon from "#/components/SvgIcon.vue";
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.use(router);
app.component("SvgIcon", SvgIcon);
router.isReady().then(() => {
app.mount("#app");
});
However, I don't have access to the Pinia Store, which doesn't seem to be initialized yet, although it is called before in the main.js
Before what? Pinia instance is created with const pinia = createPinia(); after the router module is imported - while it is imported, all side-effects including the call to createRouter() are executed. Once the router is created it begins it's initial navigation (on client - on server you need to trigger it with router.push()) - if you happen to be at URL matching the route with guard that is using Pinia store, the useProcessStore() happens before Pinia is created...
Using a store outside of a component
You have two options:
either you make sure that any useXXXStore() call happens after Pinia is created (createPinia()) and installed (app.use(pinia))
or you pass the Pinia instance into any useXXXStore() outside of component...
// store.js
import { createPinia } from "pinia";
const pinia = createPinia();
export default pinia;
// router.js
import pinia from "#/store.js";
import { useProcessStore } from "#/store/process";
const routes: Array<RouteRecordRaw> = [
{
path: "/processes/:id",
name: "ProcessView",
component: loadView("ProcessView", "processes/"),
beforeEnter: () => {
const processStore = useProcessStore(pinia ); // <-- passing Pinia instance directly
console.log(processStore);
},
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
// main.js
import { createApp } from "vue";
import App from "#/App.vue";
import store from "#/store.js";
import router from "#/router";
const app = createApp(App);
app.use(store);
app.use(router);
router.isReady().then(() => {
app.mount("#app");
});
Hope this would be helpful.
Vue provide support for some functions in which we need store(outside of the components).
To fix this problem I just called the useStore() function inside the function provided by Vue(beforeEach) and it worked.
Reference : https://pinia.vuejs.org/core-concepts/outside-component-usage.html
Example :
import { useAuthStore } from "#/stores/auth";
.
.
.
.
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
router.beforeEach(async (to, from) => {
const authStore = useAuthStore();
// use authStore Here
});
I have same problem to access the store in "beforeEach" method for managing authorization.
I use this method in main.js, not in router.js. in router.js store is not accessible.
create pinia instance in piniCreate.js
//piniaCreate.js
import { createPinia } from "pinia";
const pinia = createPinia();
export default pinia;
after that create my store in mainStore.js
import { defineStore } from 'pinia'
export const mainStore = defineStore('counter', {
state: () => {
return {
user: {
isAuthenticated: isAuthen,
}
}
},
actions: {
login(result) {
//...
this.user.isAuthenticated = true;
} ,
logOff() {
this.user.isAuthenticated = false;
}
}
});
Then I used beforeEach method in the main.js
//main.js
import { createApp } from 'vue'
import App from './App.vue'
import pinia from "#/stores/piniaCreate";
import { mainStore } from '#/stores/mainStore';
import router from './router'
const app = createApp(App)
.use(pinia)
.use(router)
const store1 = mainStore();
router.beforeEach((from) => {
if (from.meta.requiresAuth && !store1.user.isAuthenticated) {
router.push({ name: 'login', query: { redirect: from.path } });
}
})
app.mount('#app');
You can pass the method in the second parameter of definestore:
store.js
export const useAppStore = defineStore('app', () => {
const state = reactive({
appName: 'App',
appLogo: ''
})
return {
...toRefs(state)
}
})
router.js
router.beforeEach((to, from, next) => {
const apppStore = useAppStore()
next()
})
I have resolved this by adding lazy loading
const routes = [
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]

Vue <router-view /> doesn't show anything

So I deploy this app in my server using sub directories like MyServer.com/vue/.
Inside my App.vue only show <router-view />, on local this application runs smoothly, and there is no error on console.
App.vue:
<template>
<router-view/>
</template>
<script>
export default { };
</script>
<style></style>
route.js:
import { createRouter, createWebHistory } from "vue-router";
const routes = [
{
path: "/",
name: "Home",
component: () => import("../views/Home.vue"),
redirect: "/dashboard",
children: [
// Children routes
],
},
{
path: "/login",
name: "Login",
component: () => import("../views/Login.vue"),
},
];
const router = createRouter({
history: createWebHistory(),
routes,
mode: 'hash',
});
export default router;
main.js:
import { createApp } from "vue";
import App from "./App.vue";
import router from "./route";
import ElementPlus from "element-plus";
import { Chart, registerables } from "chart.js";
import "element-plus/dist/index.css";
import "./styles/index.scss";
const app = createApp(App);
app.use(router);
app.use(ElementPlus);
app.use(Chart.register(...registerables));
app.mount("#app");

Vue3 route.query empty

Trying to pass route query to axios request, but it is empty..
route.query returns empty in mounted. route.queryreturns {"filter[city]": "Vilnius" } in axios then
nextTick doesn't solve issue. Any tips?
import { ref, onMounted, nextTick } from 'vue';
import axios from 'axios';
import { useRouter, useRoute } from 'vue-router';
export default {
setup() {
const router = useRouter();
const route = useRoute();
onMounted(() => {
console.log(route.query); // log is {}
fetchApartments();
});
function fetchApartments() {
console.log(route.query); // log is {}
axios.get('/api/apartments').then(response => {
console.log(route.query); // log is { "filter[city]": "Vilnius" }
});
}
}
}
Route navigation is asynchronous. You need to wait for router.isReady for queries to be available
import {useRouter, useRoute} from 'vue-router';
export default {
setup() {
const router = useRouter();
const route = useRoute();
onMounted(async () => {
await router.isReady();
console.log(route.query);
});
}
}
Update your code like this:
...
import { computed } from 'vue'
...
and inside setup()
const route = useRoute();
const query = computed(() => route.query)
The missing part here is computed property.

Access router instance from my service

I create a auth service (src/services/auth.js), with just functions and properties ..
export default {
login() { ... }
...
}
Inside login function, I need to redirect user
router.go(redirect)
How can I retrieve router instance?
Context
In my src/main.js file, i create a router ..
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import route from './routes'
const router = new VueRouter({
history: false,
linkActiveClass: 'active'
})
route(router)
const App = Vue.extend(require('./App.vue'))
In my src/routers.js is just map routes
export default function configRouter (router) {
router.map({ .. })
}
You should export the router instance and then import it into the auth.js service.
Here is my workaround with some improvements:
src/routes.js
export default {
'/': {
component: {...}
},
'/about': {
component: {...}
},
...
}
src/router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Routes from './routes'
Vue.use(VueRouter)
const router = new VueRouter({...})
router.map(Routes)
// export the router instance
export default router
src/main.js
import Router from './router'
import App from './app'
Router.start(App, '#app')
src/services/auth.js
import Router from '../router'
export default {
login () {
// redirect
Router.go('path')
}
}
Is your auth service a Vue component?
If so, you should be able to change routes with:
this.$router.go('/new/route');