gridsome where to add router meta data - vue.js

I want to password protect specific routes and would like to add a meta data to every route like this:
{
path: '/route-path',
name: 'route-name',
component: ComponentName,
meta: {
requiresAuth: true
}
}
So I can check this in
router.beforeEach((to, from, next)
I have access to router.beforeEach in main.js but where do I add the auth flag to each route? gridsome.config.js does not seem to work?

Although it's not currently documented you can use the create page API and pass it a route property, for example...
src/pages.js
module.exports = [
{
path: '/',
route: {
name: 'index',
meta: {
requiresAuth: false
}
},
component: './src/views/Index.vue'
}
]
gridsome.server.js
const pages = require('./src/pages')
module.exports = function (api) {
api.createPages(({ createPage }) => {
for (const page of pages) {
createPage(page)
}
})
}
I also moved the page components into a src/views directory to avoid route auto generation.

Related

Nuxt create a route without creating a page

I want to create a route (/logout) in nuxt without creating a page (.vue) for it.
In the past I would just create the route in my routes file and write some code in the enclosure.
Something like this in my nuxt config I thought would work but I get a not found
router: {
routes: [
{
path: '/fish',
redirect: to => {
return { path: 'shark', query: null }
}
}
],
middleware: 'auth'
},
Can this be done?
In your nuxt config file, you can leverage the extendedRoutes function off of the router object, something like this:
router: {
extendedRoutes(routes, resolve) {
routes.push({
name: '',
path: '',
component: resolve(__dirname, 'pages/your/page.vue')
})
}
}

How to not be able to access manually /login after you logged in - VueJS?

I'm learning VueJS from an Udemy course. In the module about authentication, the instructor didn't make the whole process, so I had to try it by my self for 2 days but I succeeded 90%.
The backend is on firebase, so after login with correct data, I get back a token that I send it to local storage.
With the code that I make it, you can't see the dashboard if you are not authenticated(even you try the route manually), but what I don't like is that you can see the login page after you are authenticated(if you type /signin).
This last part is not normal to be. So if you are authenticated, when you try manually to go to /signin, you can.
In the router.js:
const routes = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: WelcomePage },
{ path: '/signup', component: SignupPage },
{ path: '/signin', component: SigninPage },
{ path: '/dashboard', component: DashboardPage}
]
});
routes.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/signin', '/signup'];
const authRequired = !publicPages.includes(to.path);
const loggedIn = localStorage.getItem('token');
console.log(loggedIn);
if (authRequired && !loggedIn) {
return next('/signin');
}
next();
});
And in store.js, inside login action:
if (localStorage.getItem('token')) {
router.replace("/dashboard");
}
Any idea what to do to /login and /register routes after login so to not be able to see them, even you manually try these routes?
If the user will try manually /signin or /signup, I want to be redirected to /dashboard.
In my vue application I just use the router.beforeEach method with meta data plus the state of my token which I pull from my store.
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
var token = store.getters.loggedIn;
if (!token ) {
next({
path: '/login',
})
} else {
next()
}
}else if (to.matched.some(record => record.meta.requiresVisitor)) {
if (token) {
next({
path: '/',
})
} else {
next()
}
}
})
It checks each time the route changes.
The requiresVisitor meta is something I placed in my router object
{
// this is can only be viewed if not logged in.
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "login" */ './views/Login.vue'),
props: true,
meta: {
requiresVisitor: true,
layout: "landing",
},
},
{
// this can only be viewed if logged in.
path: '/',
name: 'dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ './views/Dashboard.vue'),
props: true,
meta: {
requiresAuth: true,
layout: "default",
},
},
you can read more about route guards Here
theses methods are typically used in the entry point to the app main.js or in your router.js file.
You can add a per-route guard (https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard) to make the logic only run when /signin and /signup is matched, but if you want to keep it in the loop that runs over all routes you're on the right track -- you just need to invert your logic.
So what you want do is to add another if statement, checking if isLoggedIn is true, and that you're trying to access a public page, and in that case redirect the user to the /dashboard route.
if (!authRequired && loggedIn) {
next('/dashboard');
return;
}
Best example of redirection using beforeEach
const routes = [
{
path: "/",
name: "login",
component: Login,
meta:{requiresVisitor: true},
},
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
meta:{requiresVisitor: false},
}];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
//Check the user is loged in If yes then move to next url.If not loged
in so move in else and check the meta and move into next other wise is
redirect my index url
router.beforeEach((to, from, next) => {
const isLogged = JSON.parse(localStorage.getItem('username'));
if (isLogged) next()
else{
if(to.meta.requiresVisitor) next()
else next('/')
}
})

Vue.js router - conditional component rendering

routes: [
{
path: '/',
name: 'home',
get component(){
if(Vue.loggedIn){
return Home
}else{
return Login
}
}
}
I've added a getter and seems to work fine but any variable or function i use in the if statement is undefined. even i've tried using global prototype.$var and mixin functions still with no success.
All i need is if a user is logged in the path '/' renders Dashboard view and if not then Login is rendered to '/'.
Note: I've used beforeEnter: and it works fine. but i don't want redirection.
Using your approach this is what I found is working:
routes: [
{
path: '/',
name: 'home',
component: function () {
if(loggedIn){
return import('../views/Home.vue')
}else{
return import('../views/Login.vue')
}
}
}
In my application I use a router.beforeEach to check if user has logged in. I used a getter to check if logged in state is correct. I also used meta to only show views depending on if user has logged in or not.
I applied this code to the entry point of the application main.js
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.loggedIn) {
next({
path: '/login',
})
} else {
next()
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
// this route is only available to a visitor which means they should not be logged in
// if logged in, redirect to home page.
if (store.getters.loggedIn) {
next({
path: '/',
})
} else {
next()
}
}
})
In my router.js file I have the meta set as this
routes: [
{
// this is the route for logging in to the app
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "login" */ './views/Login.vue'),
props: true,
meta: {
requiresVisitor: true,
layout: 'landing',
},
},
{
// this is the dashboard view
path: '/',
name: 'dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ './views/Dashboard.vue'),
meta: {
requiresAuth: true,
layout: 'default',
breadCrumb: [
{ name: 'Dashboard' }
]
}
},
]
notice the meta object. if you are using vue devtools you will see that these params are available to use for validation.

Vuejs Display a router name in Component

How can I display a router name in a component ?
Example:
const routes = [
{ path: '/documents', component: Documents, name:"Documents" ,props:true},
{ path: '/queries', component: Queries, name:"Queries", props:true}
]
I want to display the name property as a title in the component. Is this possible? how?
props:true will convert path parameters to properties:
{ path: '/documents/:name', component: Documents, name:"Documents", props:true},
You can use an object instead of true and then send in a string.
{ path: '/documents', component: Documents, name:"Documents", props:{ name:'Documents'}},
In your component, register the property
props: { name:String }
And then use it in a template like this:
<div>{{name}}</div>
You can also refer to the route name using the components $route object
<div>{{$route.name}}</div>
To specify title to a component you can use router's meta property, Link
const routes = [
{
path: '/documents',
component: Documents,
name:"Documents" ,
props:true,
meta: {
title: 'Documents'
}
},
{
path: '/queries',
component: Queries,
name:"Queries",
props:true,
meta: {
title: 'Queries'
}
}
]
In main.js,
import router from '#/routes'
router.beforeEach((to, from, next) => {
document.title = `Currently at - ${to.meta.title}`
next()
})

Occurs dead loop in router.beforeEach in vue, vue-router

I have issue that i still cant fix it after i try some solution thought google search.
I am using router.beforeEach to check token exist.
If I no login and input localhost/overview in url bar directly,
it need to redirect login page and url redirect to localhost/login but fail and show the error message below,
Maximum call stack size exceeded
How can i modify the router.beforeEach method ?
In router.js
import Vue from 'vue'
import store from '#/store/index'
import Router from 'vue-router'
import Overview from '#/components/Overview'
import Login from '#/components/Login'
Vue.use(Router)
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Login',
component: Login,
meta: {
requiresAuth: false
}
},
{
path: '/overview',
name: 'Overview',
component: Overview,
meta: {
requiresAuth: true
}
},
{
path: '*',
redirect: '/login',
meta: {
requiresAuth: false
}
}
]
}
router.beforeEach((to, from, next) => {
let token = store.state.token
if (token) {
if (to.query.redirect) {
next({path: to.query.redirect})
} else {
if (['/login'].includes(to.path)) {
next({path: '/overview'})
} else {
next()
}
}
} else {
let requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth) {
next({path: '/login', query: { redirect: to.fullPath }})
} else {
next()
}
}
})
export default router
Be sure that your logging path does not require auth itself/that your mechanism to detect if a page needs auth is correct.
Keep in mind that your navigation guard function will be called each time a route is reached, including when you are redirecting the user programatically in your navigation guard itself. So you should take that in account to create a function that will not loop (i.e trigger a redirect that trigger a redirect...).