How to catch all routes starting with admin - vue-router

In my vuejs 3 application, I'm trying to add a navigation drawer to all admin routes. So, I need to catch all routes starting with admin (this includes "/admin", "/admin/users", "/admin/users/10" etc). I tried "/admin*", not working. I've tried googling around, no solution too.

One possible approach:
In the component where you render the navigation drawer, you could extract the route path portion that you need and then check if the current route is allowed to render the navigation drawer:
So you could create a function like this:
import { useRoute } from 'vue-router';
const route = useRoute()
//We will pass a parameter to reuse the function in case you need it.
const routeIsAllowed = (requiredRoute) => {
const routePath = route.path.substring(0, requiredRoute.lenght);
return routePath === requiredRoute
}
Then in your template you just render conditionally based on the route path name matching your criteria:
<NavigationDrawer v-if="routeIsAllowed('/admin')" />
There might be a different approach but I think is a valid solution with reutilization in mind.
Also if you want to get an array of routes in a nested route configuration in Vue Router, you just need to get it like this:
full route path: /admin/users
route.matched[0].path // '/admin'
route.matched[1].path // '/users'
Basically matched will give you an array of each route path, which can be accessed with the index value and .path at the end as a string.

Related

Svelte Dynamic Route Param - Passing Multiple Params?

Is there a way to pass multiple params into a dynamic route?
For example I have a search result page that is looping through results
{#each results as result}
<a href="../book/{result.key}">
{result.title}
</a>
{/each}
I am passing the key to a [slug] route and I am using the key to call an API.
My end goal is to have the result.title be the dynamic route param, but I also want to pass the result.key so I am able to call the API.
This post: Passing mulitple parameters to dynamic route in Svelte is over a year old and I was wondering if there is now a way to do this and I would like to keep the route as /title instead of /title/key or /key/title as suggested in that post.
You will have to embed both of them somehow in the URL. Perhaps a construction like /book/<title>?key=<key> would do for you ? I notice that would be the 'other option' from the post you linked, but the answer there is outdated.
Nowadays you would either in +page.sveltejs or +page.server.js do
export const load = (async ({ params, url }) => {
const title = params.title;
const key = url.searchParams.get('key');
}
But here you would have to be aware that key could be empty.
One last option (that I personally don't like) is to have the urls in the form of /book/<title>-<key>, this is something you sometimes see with product sites.
In this case your file will be called /book/[title]-[key]/+page.svelte
And you just extract the params as normal:
export const load = (async ({ params }) => {
const { key, title } = params;
}

Choose which component to show on certain route in Vue.js

Is it possible to set a condition in a route to decide which component to show in it? Something like this:
let someBoolean = true;
const routes = [
{ path: '/foo', component: someBoolean ? Foo : Baz },
{ path: '/bar', component: Bar }
]
And boolean value can be changed. Depending on that component should also be chosen.
According to Codesandbox, it is possible.
However, the routes tree is built at the app startup, so if you change the variable through an action from your app, nothing should happen, the tree shouldn't be built again.
EDIT:
Vue Router has an API that allows you to update your tree after the tree was built.
You have Router.addRoute(), and this trick that allows you to reset the tree to its initial state and conditionally add the route you want to keep.

Vue Router - How to pass along query params between routes

I have the following scenario...
When a user visits the route /intended/page, they are redirected to another route, say /foo/page?next=/intended/page. I add a query param next=/intended/page to keep the original route. From the redirect route, the user goes through a series of other pages/components , say /bar/page then /baz/page at the end of which I want to take them to the original route. The problem is how to pass along next to bar and baz routes. I figure I could store the query param in Vuex but maybe there is a simpler way using vue router. I tried doing it in a global guard
router.beforeEach((to, from, next) => {
if (from.query.next) next({path: to.path, query: {next: from.query.next}});
else next();
});
but I end up in an infinite loop. Any ideas?
If you want to edit querystring parameters runtime, before each route, you just need to edit your to.query object:
example:
to.query.site = 'mysite';
and then:
next({path: to.path, query: to.query})
If your url was: /#/?name=Gianni
It will redirect to: /#/?name=Gianni&site=mysite

How to tell if Vue-Router navigation hook was triggered by "push"?

I need to perform a certain action whenever a call to router.push is triggered.
I'm trying to use Vue-Router's navigation guards for this, but there is no way to tell, inside of its callback, what method (go/push/back/replace) triggered it.
router.beforeResolve((to, from) => {
// Do something only if this was triggered by "push"
});
Just hook vue-router push/back/replace function before Vue.use(vue-router),
then get navigation type by call
this.$router.customNaviType;
import Vue from 'vue'
import Router from 'vue-router'
const routerPush = Router.prototype.push;
// rewrite push
Router.prototype.push = function push(location) {
this.customNaviType = "push";
return routerPush.call(this, location).catch(error => error)
}
const routerBack = Router.prototype.back;
// rewrite back
Router.prototype.back = function back() {
this.customNaviType = "back";
return routerBack.call(this);
}
const routerReplace = Router.prototype.replace;
// rewrite replace
Router.prototype.replace = function replace(location) {
this.customNaviType = "replace";
return routerReplace.call(this, location).catch(error => error)
}
Vue.use(Router)
https://router.vuejs.org/guide/essentials/navigation.html
By my understanding, only push method will increase the history.length by one.
Maybe use a global variable to keep check window.history.length. If it increase, then you can trigger your push event.
For example:
router.beforeResolve((to, from) => {
if (window.history.length > window.last_history_length) {
trigger_your_push_event();
}
window.last_history_length = window.history.length;
}
});
It can not be catched by navigation guards directly:
But,
using the state of your app you can have a better idea which operation is done. You can do it by saving the current and your last route to your state using the guard afterEach. Once you know them, you can compare them with from and to parameters in e.g. beforeEach to get know whether it is a push or back. You can probably add more metadata to your routes so you get know more about your routes to decide whether it is replaced by some kind of other type route:

Nuxt send data between 2 components

welcome to this topic. i recently tried to use the Nuxt framework to make my web-application but i ran into a problem.
In my default layout i have two components. a header component and a sidebar component. if i click on the hamburger icon in the header component the sidebar needs to get smaller or bigger depending on the hamburger icon state (true or false)
so to make it more complicated i don't want to use a prop to send it through the other component. i want to make it as a template so people can use it easy. can i transform a local component variable to a global variable other components can use?
so the code i have now is like this:
this is the index page
this is the header component
this is the sidebar component
as you can see i trigger the hamburgerstate on the header component page.
i want to access that state in the sidebarcomponent to so i can adjust the sidebar
the one thing that's IMPORTANT is that it needs to be as simple as possible so people who use this template later don't have to add unnecessary work
any possibilities this can work?
The simplest way to achieve a global variable is to set it as a state element and have a mutation for changing it. As your 'hambuger' is a boolean there is no need to pass parameters to the mutation making it all the easier.
You may want to have a named module in you store to handle this but I'll just put it in store/index.js for now.
export const state = () => ({
hamburger: true
})
export const mutations = {
changeHamburger (state) {
state.hamburger = !state.hamburger
}
}
Then in any page or component you can access that state element:
Component.vue
<script>
import { mapMutations } from 'vuex'
export default {
computed: {
hamburger () {
return this.$store.state.hamburger
}
},
methods: {
...mapMutations({
hamburgerChange: 'changeHamburger'
})
}
}
</script>
So this means you can now use the computed property 'hamburger' in your component and can change it by calling 'hamburgerChange', eg <v-btn #click="hamburgerChange">.